Reestructuración - separación de la vista

This commit is contained in:
jp.av.dev 2022-04-20 15:56:56 -04:00
parent f6a008bf46
commit da563be55d
7 changed files with 649 additions and 328 deletions

3
.gitignore vendored
View File

@ -1 +1,4 @@
__pycache__/
caldera_esp/confidencial.h
config.cfg
TODO.txt

106
README.md
View File

@ -1,82 +1,82 @@
# Automatizacion de Caldera
Enciende o apaga el termo según configuración. Admite hasta dos
horarios de funcionamiento al día, ajustables en modo 3.
El funcionamiento autonomo es la opción por defecto (modo 1).
Funcionamiento manual espera instrucción para realizar acción de
encendido o apagado (modo 5).
Hora y fecha ajustables en el modo 2
Posiciones del servo al encender o apagar el termo (modo 4).
Son dos posiciones, ya que el servo realiza movimiento repetitivo
con para asegurar el accionamiento mecánico del interruptor del termo.
El modo 6 permite mover libremente el servo (desde 16 hasta 144).
Útil para probar ajustes.
***Control de encendido para caldera electrica.***
Enciende o apaga el termo según configuración. Admite hasta dos horarios
de funcionamiento al día, ajustables en modo 3.
El funcionamiento autonomo es la opción por defecto (modo 1).
Funcionamiento manual espera instrucción para realizar acción de encendido
o apagado (modo 5).
Hora y fecha ajustables en el modo 2.
Hardware utilizado:
- ATmega328p (ArduinoNano old bootloader)
- RTC-DS3231
- Servo
- esp8266 (ESP01)
Posiciones del servo al encender o apagar el termo (modo 4). Son dos posiciones,
ya que el servo realiza movimiento repetitivo para asegurar el accionamiento
mecánico del interruptor del termo.
Arduino funciona de forma autonoma, no requiere del módulo wifi.
El ESP-01 funciona como interface web entre el usuario y el puerto serie de arduino.
El modo 6 permite mover libremente el servo (desde 16 hasta 144). Útil para probar ajustes.
caldera.sh: utilidad para enviar controlar caldera por terminal.
### Hardware utilizado:
- [ATmega328p](https://en.wikipedia.org/wiki/Arduino_Nano) (ArduinoNano old bootloader)
- [Real time clock](https://en.wikipedia.org/wiki/Real-time_clock) (RTC-DS3231)
- [Servo](https://es.wikipedia.org/wiki/Servomotor)
- [esp8266](https://en.wikipedia.org/wiki/ESP8266) (ESP01)
- [buck converter](https://en.wikipedia.org/wiki/Buck_converter)
**Arduino** funciona de forma autonoma, no requiere del módulo wifi.
**ESP-01** funciona como interface web basica entre el usuario y el puerto serie de arduino.
### Herramientas de control (scripts)
- [caldera.sh](.scripts/caldera.sh) (bash)
- [caldera.py](.scripts/caldera.py) (python)
-----
## Control de horario de encendido caldera electrica
## Arduino
Control de horario de encendido caldera electrica.
Trabaja de forma autonoma y/o comandado por puerto serie (**115200 baudio**).
* 3 Modos de Operación
- Automatizado (1, por defecto)
- Manual (5)
- Libre (6)
* 3 Modos de Configuracion
- Configuracion de fecha y hora (2)
- Configuracion horas de encendido y apagado (3)
- Configuracion de posiciones de encendido y apagado (4)
* 3 Modos de Configuración
- Configuración fecha y hora (2)
- Configuración horas de encendido y apagado (3)
- Configuración de posiciones de encendido y apagado (4)
Arduino envia cada segundo los valores actuales de las variables de control al puerto serie.
```
ej.
1,0,5,7,16,18,120,90,45,62,1,42,24,14,7,2021
ej.
1,0,5,7,16,18,120,90,45,62,1,42,24,14,7,2021
1 > modo,
| 0 > estado termo (O = apagado, 1 = Encendido)
| | 5 > hora de encendido
| | | 7 > hora de apagado
| | | | 16 > 2da hora de encendido (opcional)
| | | | | 18 > 2da hora de apgado (opcional)
| | | | | | 120 > 1ra posicion encendido
| | | | | | | 90 > 2ra posicion encendido
| | | | | | | | 45 > 1ra posicion apagado
| | | | | | | | | 62 > 2ra posicion apagado
| | | | | | | | | | 1 > hora en RTC
| | | | | | | | | | | 42 > minutos en RTC
| | | | | | | | | | | | 24 > segundos en RTC
| | | | | | | | | | | | | 14 > dia en RTC
| | | | | | | | | | | | | | 7 > mes en RTC
| | | | | | | | | | | | | | | 2021 > año en RTC
1,0,5,7,16,18,120,90,45,62,1,42,24,14,7,2021
1 ______________________________________________ modo,
| 0 ____________________________________________ estado termo (O = apagado, 1 = Encendido)
| | 5 __________________________________________ hora de encendido
| | | 7 ________________________________________ hora de apagado
| | | | 16 _____________________________________ 2da hora de encendido (opcional)
| | | | | 18 __________________________________ 2da hora de apagado (opcional)
| | | | | | 120 ______________________________ 1ra posicion encendido
| | | | | | | 90 ___________________________ 2ra posicion encendido
| | | | | | | | 45 ________________________ 1ra posicion apagado
| | | | | | | | | 62 _____________________ 2ra posicion apagado
| | | | | | | | | | 1 ___________________ hora en RTC
| | | | | | | | | | | 42 ________________ minutos en RTC
| | | | | | | | | | | | 24 _____________ segundos en RTC
| | | | | | | | | | | | | 14 __________ dia en RTC
| | | | | | | | | | | | | | 7 ________ mes en RTC
| | | | | | | | | | | | | | | 2021 ___ año en RTC
1,0,5,7,16,18,120,90,45,62,1,42,24,14,7,2021
```
-----
## ESP01
Establece comunicación serial con arduino (**115200 baudio**).
Interface web sencilla para consulta y configuraciones
Interface web básica para consulta y configuraciones.
Archivo de configuracion ***confidencial.h***
```c
@ -105,7 +105,8 @@ const char* password = "password";
Scripts para enviar peticiones web al ESP.
### caldera.sh
### Bash
[caldera.sh](./scripts/caldera.sh)
```
==============================
@ -134,6 +135,7 @@ const char* password = "password";
```
### caldera.py
### Python
[caldera.py](./scripts/caldera.py)
![python_script](./scripts/script_python.png)

View File

@ -1,7 +1,25 @@
## Utilidades
# Utilidades
Scripts para enviar peticiones web al ESP.
### caldera.sh
## Bash
```
─ 📂️ scripts
├── 📄️ caldera.sh
└── 📄️ config.cfg
```
Archivo de configuración
***./config.cfg***
```cfg
[esp01]
URL = <direcion_ESP>
```
Dependencias
- curl
- grep
- cut
Correr: ` ./caldera.sh `
```
==============================
@ -29,7 +47,27 @@
Ingresa Opcion :
```
----
### caldera.py
## Python
```
─ 📂️ scripts
├── 📄️ caldera.py
├── 📄️ config.cfg
└── 📄️ vista_term.py
```
Archivo de configuración
***./config.cfg***
```cfg
[esp01]
URL = <direcion_ESP>
```
Dependencias:
- requests
- colorama
Correr: ` ./caldera.py ` o ` python caldera.py `
![python_script](./script_python.png)

View File

@ -1,296 +1,176 @@
#!/usr/bin/python3
#!/usr/bin/env python3
"""
Script de control Caldera autmatizada Arduino+ESP01
Script de control Caldera automatizada [Arduino]+[ESP01]
"""
import os
import sys
from time import sleep
import configparser as cfg
import vista_term as vt
try:
parser = cfg.ConfigParser()
parser.read('config.cfg')
ESP01 = parser.get('esp01', 'URL')
except cfg.Error as ex:
print('Error al leer archivo de configuración')
sys.exit()
try:
import requests
from colorama import Fore, Back, Style
except ModuleNotFoundError as ex:
print("Debes instalar los modulos necesarios\n")
print(ex)
sleep(2)
sys.exit()
ESP01 = "http://<IP_ESP>"
clear = lambda: os.system('clear') if os.name == 'posix' else os.system('cls')
def enviar_consulta(consulta):
"""Retorna la respuesta a la petición GET *consulta*
:consulta: str ( consulta creada por consultas() )
:returns: str ( respuesta del GET request )
"""
resp = requests.get(consulta)
return resp.text
def consultas(modo, *args):
orden = '?'
for indx, arg in enumerate(args):
orden += str(indx+1)+'='+str(arg)+'&'
resp = enviar_consulta(ESP01+modo+orden[:-1])
def consultas(modo, id_modo='', datos=['']):
"""Crea la petición GET según si los datos son list o str
Retorna la respuesta de enviar_consulta()
:modo: str (sub-menu)
:id_modo: str (id modo de operacion)
:datos: list[str] | str
:returns: str (respuesta del GET request)
"""
if id_modo != '':
modo = modo + '?1=' + id_modo
orden = ''
cont = 2
if type(datos) is list:
if len(datos) == 1:
orden = ''
else:
for dato in datos:
if dato != '':
orden += '&' + str(cont) + '=' + str(dato)
cont += 1
else:
orden += '&' + str(cont) + '=' + str(datos)
resp = enviar_consulta(ESP01 + modo + orden)
return resp
def pantallas(pantalla, vals):
if pantalla == '':
if vals[0] == '\n1':
vals[0] = ' AUTO '
elif vals[0] == '\n5':
vals[0] = ' MANUAL '
elif vals[0] == '\n6':
vals[0] = ' LIBRE '
else:
vals[0] = '¡¡¡ERROR!!!'
for i in range(10,15):
if int(vals[i]) < 10:
vals[i] = '0'+vals[i]
for i in range(2,6):
if int(vals[i]) < 10:
vals[i] = ' '+vals[i]
clear()
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
if vals[1] == '1':
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" ESTADO TERMO "+Style.RESET_ALL+
Fore.GREEN+Back.BLUE+Style.BRIGHT+f" ENCENDIDO " + Style.RESET_ALL)
elif vals[1] == '0':
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" ESTADO TERMO "+Style.RESET_ALL+
Fore.RED+Back.BLUE+Style.BRIGHT+f" APAGADO " + Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" MODO "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f"{vals[0]}" + Style.RESET_ALL)
print(Fore.LIGHTGREEN_EX+Back.LIGHTBLACK_EX+
f" {vals[10]}:{vals[11]}:{vals[12]} {vals[13]}/{vals[14]}/{vals[15]} "+
Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" ON-1 "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[2]} " + Style.RESET_ALL, end='')
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" OFF-1 "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[3]} " + Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" ON-2 "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[4]} " + Style.RESET_ALL, end='')
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" OFF-2 "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[5]} " + Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Menu de Opciones "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" 1.- Modo Autonomo "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" 2.- Ajustar hora y fecha "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" 3.- Ajustar temporizador "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" 4.- Calibrar servo "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" 5.- Modo Manual "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" 6.- Modo Libre "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" 0.- Salir "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" ⏎.- Actualizar "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Ingresa una opción "+Style.RESET_ALL,
end='\b\b\b\b\b\b')
elif pantalla == '1':
print(Fore.MAGENTA+Back.BLUE+Style.BRIGHT+vals+Style.RESET_ALL)
elif pantalla == '2':
for i in range(0,5):
if int(vals[i]) < 10 and vals[i][0:1] != '0' :
vals[i] = '0'+vals[i]
clear()
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Valores actuales en RTC "+Style.RESET_ALL)
print(Fore.LIGHTGREEN_EX+Back.LIGHTBLACK_EX+
f" Hora : {vals[0]}:{vals[1]}:{vals[2]} "+Style.RESET_ALL)
print(Fore.LIGHTGREEN_EX+Back.LIGHTBLACK_EX+
f" Fecha : {vals[3]}/{vals[4]}/{vals[5]} "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Ajustando fecha y hora "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
elif pantalla == '3':
for i in range(0,4):
if int(vals[i]) < 10 and vals[i][0:1] != ' ':
vals[i] = ' '+vals[i]
clear()
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Horario Temporizador "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" ON-1 "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[0]} " + Style.RESET_ALL, end='')
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" OFF-1 "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[1]} " + Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" ON-2 "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[2]} " + Style.RESET_ALL, end='')
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" OFF-2 "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[3]} " + Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Ingresa nuevo horario "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
elif pantalla == '4':
for i in range(0,4):
if int(vals[i]) < 100:
vals[i] = ' '+vals[i]
clear()
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Configuracion Actual "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" 1 Posición ON "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[0]} " + Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" 2 Posición ON "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[1]} " + Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" 1 Posición OFF "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[2]} " + Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" 2 Posición OFF "+Style.RESET_ALL+
Fore.LIGHTRED_EX+Back.BLUE+Style.BRIGHT+f" {vals[3]} " + Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Ingresa nuevos valores "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
elif pantalla == '5':
clear()
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Accionamiento Manual "+Style.RESET_ALL)
if vals[0] == '1':
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" ESTADO TERMO "+Style.RESET_ALL+
Fore.GREEN+Back.BLUE+Style.BRIGHT+f" ENCENDIDO " + Style.RESET_ALL)
elif vals[0] == '0':
print(Fore.BLUE+Back.LIGHTWHITE_EX+Style.DIM+" ESTADO TERMO "+Style.RESET_ALL+
Fore.RED+Back.BLUE+Style.BRIGHT+f" APAGADO " + Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Encender o Apagar "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
elif pantalla == '6':
clear()
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Movimiento Libre "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+"==========================="+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" Ingresa posición (16..164)"+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
def solicita_dato(valid, mensaje):
invalido = True
while invalido:
intentos=0
def datos_a_lista() -> list[str] :
"""Retorna el str recibido de consultas() como una lista, valida el largo
de la lista, añade 0 o ' ' a valores, según sea necesario para el correcto
formateo del texto a mostrar.
:returns: list[str] ( len(list) = 16 )
"""
datos = []
global intentos
while True:
try:
dato = input(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+mensaje+Style.RESET_ALL)
dato = int(dato)
if valid[0] < dato < valid[1]:
invalido = False
return dato
raise ValueError
except ValueError:
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+
"Ingresa un número válido "+Style.RESET_ALL)
def solicita_dato_str(valid, mensaje):
invalido = True
while invalido:
try:
dato = input(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+mensaje+Style.RESET_ALL)
if dato in valid:
invalido = False
return dato
raise ValueError
except ValueError:
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+
" Debes ingresar \'on\' u \'off\' "+Style.RESET_ALL)
intentos = 0
while True:
#res[1] = 'ENCENDIDO' if res[1] == '1' else 'APAGADO' if '0' else ''
res = []
try:
clear()
resp = consultas('')
for var in resp.split(','):
res.append(var)
assert len(res) == 16
pantallas('', res)
opc = input(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+":"+Style.RESET_ALL)
if opc == '0':
sys.exit()
elif opc == '1':
resp = consultas('/auto')
print(Fore.MAGENTA+Back.BLUE+Style.BRIGHT+resp+Style.RESET_ALL)
sleep(8)
resp = consultas('')
for var in resp.split(','):
datos.append(var)
assert len(datos) == 16
for i in range(10,15):
if int(datos[i]) < 10:
datos[i] = '0'+datos[i]
for i in range(2,6):
if int(datos[i]) < 10:
datos[i] = ' '+datos[i]
intentos = 0
elif opc == '2':
pantallas('2',[res[10], res[11], res[12], res[13], res[14], res[15]])
resp = consultas('/sethora', opc, solicita_dato((0,32),' DIA : '),
solicita_dato((0,13),' MES : '),
solicita_dato((2020,2100),' AÑO : '),
solicita_dato((-1,24),' HORA : '),
solicita_dato((-1,60),' MINUTO : '),
solicita_dato((-1,60),' SEGUNDO : '))
print(Fore.MAGENTA+Back.BLUE+Style.BRIGHT+resp+Style.RESET_ALL)
sleep(8)
elif opc == '3':
pantallas('3',[res[2], res[3], res[4], res[5]])
resp = consultas('/horasAcc', opc,
solicita_dato((-1,24),' 1er Encendido : '),
solicita_dato((-1,24),' 1er Apagado : '),
solicita_dato((-1,24),' 2do Ecendido (opc.): '),
solicita_dato((-1,24),' 2do Apagado (opc.): '))
print(Fore.MAGENTA+Back.BLUE+Style.BRIGHT+resp+Style.RESET_ALL)
sleep(8)
elif opc == '4':
pantallas('4',[res[6], res[7], res[8], res[9]])
resp = consultas('/setservo', opc,
solicita_dato((15,165),' 1ra Posición Encendido:'),
solicita_dato((15,165),' 2ra Posición Encendido:'),
solicita_dato((15,165),' 1ra Posición Apagado :'),
solicita_dato((15,165),' 2da Posición Apagado :'))
print(Fore.MAGENTA+Back.BLUE+Style.BRIGHT+resp+Style.RESET_ALL)
sleep(8)
elif opc == '5':
pantallas('5',[res[1]])
resp = consultas('/accion', opc, solicita_dato_str(('on','off'),
' Ingresa \'on\' u \'off\': '))
print(Fore.MAGENTA+Back.BLUE+Style.BRIGHT+resp+Style.RESET_ALL)
sleep(8)
elif opc == '6':
pantallas('6',[res[1]])
resp = consultas('/setlibre', opc, solicita_dato((15,165),' Ingresa posición :'))
print(Fore.MAGENTA+Back.BLUE+Style.BRIGHT+resp+Style.RESET_ALL)
sleep(8)
elif opc == '':
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+
Style.RESET_ALL)
print(Fore.RED+Back.YELLOW+Style.BRIGHT+" Actualizando... "+
Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+
Style.RESET_ALL)
sleep(1.5)
else:
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+
Style.RESET_ALL)
print(Fore.RED+Back.YELLOW+Style.BRIGHT+" Opción incorrecta "+
Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+
Style.RESET_ALL)
sleep(1.5)
except KeyboardInterrupt:
sys.exit()
except AssertionError:
clear()
intentos += 1
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
print(Fore.RED+Back.YELLOW+Style.BRIGHT+" Arduino no disponible "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+f" Intentando nuevamente ({intentos+1}) "+
Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
intentos += 1
sleep(2)
except ConnectionError:
clear()
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+f" Intentando conexión ({intentos+1}) "+
Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
intentos += 1
sleep(2)
except OSError:
clear()
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+f" Intentando conexión ({intentos+1}) "+
Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
intentos += 1
sleep(2)
if intentos > 4:
print(Fore.RED+Back.YELLOW+Style.BRIGHT+" Imposible conectar con "+Style.RESET_ALL)
print(Fore.RED+Back.YELLOW+Style.BRIGHT+" ESP, o Arduino, verfica "+Style.RESET_ALL)
print(Fore.RED+Back.YELLOW+Style.BRIGHT+" IP, conexión o estado de "+Style.RESET_ALL)
print(Fore.RED+Back.YELLOW+Style.BRIGHT+ " de los dispositivos. "+Style.RESET_ALL)
print(Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM+" "+Style.RESET_ALL)
sys.exit()
return datos
except KeyboardInterrupt:
sys.exit()
except AssertionError:
vt.resp_conex('assert', intentos)
intentos += 1
sleep(2)
except ConnectionError:
vt.resp_conex('conexion', intentos)
intentos += 1
sleep(2)
except OSError:
vt.resp_conex('oserror', intentos)
intentos += 1
sleep(2)
if intentos > 4:
vt.resp_conex()
sys.exit()
def main():
global intentos
while True:
# Lista con valores de los datos recibidos
vals = datos_a_lista()
clear()
vt.pant_principal(vals[0], vals[1], vals[10:16], vals[2:6])
modo_user = vt.entrada_usuario()
match modo_user:
case 's':
sys.exit()
case '1':
#vt.pant_test_valores(vals)
vt.respuesta_config(consultas('/auto'))
intentos = 0
sleep(3)
case'2':
vt.pant_config_fecha(vals[10:16])
resp_user = vt.entrada_usuario('/sethora')
vt.respuesta_config(consultas('/sethora', modo_user, resp_user))
intentos = 0
sleep(5)
case '3':
vt.pant_termporizador(vals[2:6])
resp_user = vt.entrada_usuario('/horasAcc')
vt.respuesta_config(consultas('/horasAcc', modo_user, resp_user))
intentos = 0
sleep(5)
case '4':
pos_servo = []
for val in vals[6:10]:
if int(val) < 100:
pos_servo.append(' '+val)
else:
pos_servo.append(val)
vt.pant_posic_servo(pos_servo)
resp_user = vt.entrada_usuario('/setservo')
vt.respuesta_config(consultas('/setservo', modo_user, resp_user))
intentos = 0
sleep(5)
case '5':
vt.pant_accion_manual(vals[1])
resp_user = vt.entrada_usuario('/accion')
vt.respuesta_config(consultas('/accion', modo_user, resp_user))
intentos = 0
sleep(5)
case '6':
vt.pant_servo_manual()
resp_user = vt.entrada_usuario('/setlibre')
vt.respuesta_config(consultas('/setlibre', modo_user, resp_user))
intentos = 0
sleep(5)
case '':
vt.respuesta_info()
sleep(1.5)
case 'v':
vt.respuesta_info('volver')
intentos = 0
sleep(1.5)
case _:
modo_user = vt.entrada_usuario()
vt.respuesta_info('error')
sleep(1.5)
if __name__ == "__main__":
main()

View File

@ -1,6 +1,6 @@
#!/bin/bash
#!/usr/bin/env bash
IP_CALDERA="<IP_ESP01>"
IP_CALDERA=$(grep URL config.cfg | cut -d'=' -f2)
estado_caldera() {
RESP=$(curl -s ${IP_CALDERA})

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 30 KiB

398
scripts/vista_term.py Normal file
View File

@ -0,0 +1,398 @@
"""
Gestión de pantallas (dialogos, opcs, menus, etc) y entradas de usuario.
"""
import os
import sys
from time import sleep
from caldera import main
try:
from colorama import Fore, Back, Style
except ModuleNotFoundError as ex:
print("Debes instalar los modulos necesarios\n")
print(ex)
sleep(2)
sys.exit()
clear = lambda: os.system('clear') if os.name == 'posix' else os.system('cls')
# Colores
col_rst = Style.RESET_ALL
col_menu = Fore.BLACK+Back.LIGHTBLACK_EX+Style.DIM
col_head = Fore.BLUE+Back.LIGHTWHITE_EX+Style.NORMAL
col_headGrn = Fore.GREEN+Back.MAGENTA+Style.BRIGHT
col_headRed = Fore.RED+Back.BLUE+Style.DIM
col_headLred = Fore.LIGHTRED_EX+Back.BLUE+Style.DIM
col_headBBlk = Fore.BLACK+Back.MAGENTA+Style.BRIGHT
col_headBlk = Fore.BLACK+Back.MAGENTA+Style.NORMAL
col_date = Fore.LIGHTGREEN_EX+Back.LIGHTBLACK_EX
col_error = Fore.RED+Back.YELLOW+Style.NORMAL
col_errorB = Fore.RED+Back.YELLOW+Style.BRIGHT
col_input = Fore.BLACK+Back.LIGHTBLACK_EX+Style.DIM
col_excep = Fore.BLUE+Back.LIGHTBLACK_EX+Style.DIM
col_resp = Fore.BLACK+Back.MAGENTA+Style.BRIGHT
# Dialogos
diag_bar = '==========================='
diag_spc = ' '
diag_state = [ diag_bar, ' ESTADO TERMO ', ' ENCENDIDO ', ' APAGADO ', ' - - - - ' ]
diag_modo = [ ' MODO ', ' AUTO ', ' MANUAL ',
' LIBRE ', ' ¡ERROR! ' ]
diag_hrsfun = [ ' ON-1 ', ' OFF-1 ', ' ON-2 ', ' OFF-2 ', diag_bar ]
diag_opcs = [ diag_bar, ' Menu de Opciones ', diag_spc,
' 1) Modo Autonomo ', ' 2) Ajustar hora y fecha ',
' 3) Ajustar temporizador ', ' 4) Calibrar servo ',
' 5) Modo Manual ', ' 6) Modo Libre ',
' v) Volver(en sub-menus) ', ' s) Salir ',
' ⏎) Actualizar ', diag_spc,
' Ingresa una opción \b\b\b\b\b\b:' ]
diag_setdate = [ diag_bar,' Valores actuales en RTC ', ' Hora : ', ' Fecha : ',
diag_bar, diag_spc, ' Ajustando fecha y hora ', diag_spc,
' DIA : \b\b\b\b\b\b\b',
' MES : \b\b\b\b\b\b\b',
' AÑO : \b\b\b\b\b\b\b',
' HORA : \b\b\b\b\b\b\b',
' MINUTO : \b\b\b\b\b\b\b',
' SEGUNDO : \b\b\b\b\b\b\b' ]
diag_error = [ ' Ingresa un número válido! ', ' Debes ingresar \'on\' u \'off\' ',
' Entrada no válida! ', ' Entrada incorrecta! ' ]
diag_settimer = [ diag_bar,' Horario Temporizador ', ' ON-1 ', ' OFF-1 ',
' ON-2 ',' OFF-2 ', diag_bar, diag_spc, ' Ingresa nuevo horario ',
diag_spc, ' 1er Encendido : ', ' 1er Apagado : ',
' 2do Ecendido (opc.): ', ' 2do Apagado (opc.): ' ]
diag_posservo = [ diag_bar,' Configuracion Actual ', ' 1 Posición ON ',
' 2 Posición ON ', ' 1 Posición OFF ',' 2 Posición OFF ',
diag_bar, diag_spc,' Ingresa nuevos valores ', diag_spc,
' 1ra posic. encendido : \b\b\b\b',
' 2da posic. encendido : \b\b\b\b',
' 1ra posic. apagado : \b\b\b\b',
' 2da posic. apagado : \b\b\b\b' ]
diag_accman = [ diag_bar, ' Accionamiento Manual ', diag_state[1:5],
diag_bar, diag_spc, ' Encender o Apagar ? ', diag_spc,
' Ingresa \'on\' u \'off\': \b\b\b\b' ]
diag_servman = [ diag_bar, ' Movimiento Libre ', diag_bar, diag_spc,
'Posiciónes validas (16-164)', diag_spc ,
' Ingresa posición : \b\b\b\b\b' ]
diag_excepcn = [ diag_spc, ' Error en lectura de datos ', ' Arduino no disponible ',
' Error al solicitar datos ', f' Intentando conexión (', ') ',
' Imposible conectar con ', ' ESP o Arduino, verifica ',
' IP, conexión o estado de ', ' de los dispositivos. ' ]
diag_volver = [ diag_spc, ' Actualizando... ',
' Volviendo... ', ' Seleción incorrecta ' ]
# Valores para validación
# (min, max) dia - mes - año - hora - minuto - segundo
valid_dates = [(0,32),(0,13),(2020,2100),(-1,24),(-1,60),(-1,60)]
valid_opcs = ['1','2','3','4','5','6','']
valid_hrs_timer = (-1,24)
valid_posicion = (15,168)
valid_manual = ('on', 'off')
def resp_conex(excepcion=None, intentos=0):
"""Imprime en terminal dialogos de error de conexión
:excepcion: str (tipo de error)
:intentos: int (nro. de intentos de conexión)
"""
intentos += 1
dialogos = diag_excepcn
match excepcion:
case 'assert':
clear()
print(col_menu + dialogos[0] + col_rst)
print(col_error + dialogos[1] + col_rst)
print(col_menu + dialogos[4] + str(intentos) + dialogos[5] + col_rst)
print(col_menu + dialogos[0] + col_rst)
case 'conexion':
clear()
print(col_menu + dialogos[0] + col_rst)
print(col_error + dialogos[2] + col_rst)
print(col_menu + dialogos[4] + str(intentos) + dialogos[5] + col_rst)
print(col_menu + dialogos[0] + col_rst)
case 'oserror':
clear()
print(col_menu + dialogos[0] + col_rst)
print(col_error + dialogos[3] + col_rst)
print(col_menu + dialogos[4] + str(intentos) + dialogos[5] + col_rst)
print(col_menu + dialogos[0] + col_rst)
case _:
clear()
print(col_menu + dialogos[0] + col_rst)
for dialogo in dialogos[6:10]:
print(col_errorB + dialogo + col_rst)
print(col_menu + dialogos[0] + col_rst)
def pant_servo_manual():
"""Imprime en terminal dialogos de configuración manual del servo
"""
clear()
dialogos = diag_servman[:-1]
for dialogo in dialogos:
print(col_menu+dialogo+col_rst)
def pant_accion_manual(estado):
"""Imprime en terminal dialogos de accionamiento manual del servo
:estado: str ('0' o '1')
"""
clear()
dialogos = diag_accman[0:7]
for ind, dialogo in enumerate(dialogos):
match ind:
case 2:
print(col_head+dialogo[0]+col_rst, end='')
match estado:
case '1':
print(col_headGrn+dialogo[1]+col_rst)
case '0':
print(col_headBlk+dialogo[2]+col_rst)
case _:
print(col_headBlk+dialogo[3]+col_rst)
ind+=3
case _:
print(col_menu+dialogo+col_rst)
def pant_posic_servo(pos_servo):
"""Imprime en terminal posiciones de trabajo del servo
:pos_servo: list[str]
"""
clear()
dialogos = diag_posservo[0:10]
for ind, dialogo in enumerate(dialogos):
match ind:
case 2:
print(f"{col_head}{dialogo}{col_headGrn} {pos_servo[0]} {col_rst}")
case 3:
print(f"{col_head}{dialogo}{col_headGrn} {pos_servo[1]} {col_rst}")
case 4:
print(f"{col_head}{dialogo}{col_headGrn} {pos_servo[2]} {col_rst}")
case 5:
print(f"{col_head}{dialogo}{col_headGrn} {pos_servo[3]} {col_rst}")
case _:
print(col_menu + dialogo + col_rst)
def pant_termporizador(hrs_timer):
"""Imprime en terminal horas de trabajo del servo
:hrs_timer: list[str]
"""
clear()
dialogos = diag_settimer[0:10]
for ind, dialogo in enumerate(dialogos):
match ind:
case 2:
#ind+=1
print(f"{col_head}{dialogo}{col_headGrn} {hrs_timer[0]} {col_rst}", end='')
case 3:
print(f"{col_head}{dialogo}{col_headGrn} {hrs_timer[1]} {col_rst}")
case 4:
print(f"{col_head}{dialogo}{col_headGrn} {hrs_timer[2]} {col_rst}", end='')
case 5:
print(f"{col_head}{dialogo}{col_headGrn} {hrs_timer[3]} {col_rst}")
case _:
print(col_menu + dialogo + col_rst)
def pant_config_fecha(tiempo):
"""Imprime hora y fecha en terminal, segun ESP.
:tiempo: list[str] [hora, minuto, segundo, dia, mes, año]
"""
clear()
dialogos = diag_setdate
for ind, dialogo in enumerate(dialogos):
match ind:
case 2:
print(f"{col_date}{dialogo}{tiempo[0]}:{tiempo[1]}:{tiempo[2]} {col_rst}")
case 3:
print(f"{col_date}{dialogo}{tiempo[3]}/{tiempo[4]}/{tiempo[5]} {col_rst}")
case 8:
break
case _:
print(col_menu + dialogo + col_rst)
def pant_principal(modo, estado, tiempo, hrs_timer):
"""Imprime menu principal en terminal.
:modo: str (ej. '\\n')
:estado: str estado del termo ('0','1')
:tiempo: List[str] hora y fecha
:hrs_timer: List[str] horario de accionamiento
"""
clear()
# Estado
dialogos = diag_state
print(col_menu+dialogos[0]+col_rst)
print(col_head+dialogos[1]+col_rst, end='')
match estado:
case '1':
print(col_headGrn+dialogos[2]+col_rst)
case '0':
print(col_headBlk+dialogos[3]+col_rst)
case _:
print(col_headBlk+dialogos[4]+col_rst)
# Modo de operación
dialogos = diag_modo
print(col_head+dialogos[0]+col_rst, end='')
match modo:
case '\n1':
print(col_headGrn+dialogos[1]+col_rst)
case '\n5':
print(col_headBlk+dialogos[2]+col_rst)
case '\n6':
print(col_headBlk+dialogos[3]+col_rst)
case _:
print(col_headRed+dialogos[4]+col_rst)
# Hora y Fecha
print(col_date, end='')
print(f" {tiempo[0]}:{tiempo[1]}:{tiempo[2]}", end='')
print(f" {tiempo[3]}/{tiempo[4]}/{tiempo[5]} "+col_rst)
# Horas de funcionamiento
dialogos = diag_hrsfun
print(col_head + dialogos[0] + col_rst, end='')
print(col_headBBlk + ' ' + hrs_timer[0] + ' ' + col_rst, end='')
print(col_head + dialogos[1]+col_rst, end='')
print(col_headBBlk + ' ' + hrs_timer[1] + ' ' + col_rst)
print(col_head + dialogos[2] + col_rst, end='')
print(col_headBBlk + ' ' + hrs_timer[2] + ' ' + col_rst, end='')
print(col_head + dialogos[3]+col_rst, end='')
print(col_headBBlk + ' ' + hrs_timer[3] + ' ' + col_rst)
# Opciones del menu principal
dialogos = diag_opcs[:-1]
for indx, dialogo in enumerate(dialogos):
if indx != (len(dialogos)-1):
print(col_menu+dialogo+col_rst)
else:
print(col_menu+dialogo+col_rst)
def pant_test_valores(valores):
"""Función de prueba, imprime en terminal valores de lista.
:valores: Lista de strings [ str, str, ...]
"""
for val in valores:
print(Fore.MAGENTA+Back.BLACK+Style.BRIGHT+val+Style.RESET_ALL)
def valida_entrada(valid, mensaje, tipo_dato='') -> list[str] | str:
"""Solicita entrada de usuario, imprime dialogo en terminal y
valida según tupla *valid*.
:valid: tuple (límites o alternativas válidas)
:mensaje: str (mensaje para solicitar entrada de usuario)
"""
invalido = True
err_msg = ''
while invalido:
entrada_usuario = input(col_input+mensaje+Style.RESET_ALL)
if entrada_usuario == 's':
sys.exit()
#return 's'
elif entrada_usuario == 'v':
main()
#return 'v'
match tipo_dato:
case '':
try:
entrada_usuario = int(entrada_usuario)
if valid[0] < entrada_usuario < valid[1]:
invalido = False
return str(entrada_usuario)
else:
raise ValueError
except ValueError:
err_msg = diag_error[0]
print(col_error + err_msg + Style.RESET_ALL)
case 'str':
try:
if entrada_usuario in valid:
invalido = False
return entrada_usuario
else:
err_msg = diag_error[3]
raise ValueError
except ValueError:
err_msg = diag_error[3]
print(col_error + err_msg + Style.RESET_ALL)
case _:
assert entrada_usuario in ['','str']
err_msg = diag_error[2]
print(col_error + err_msg + Style.RESET_ALL)
def entrada_usuario(caso=None) -> list[str] | str :
"""Retorna la(s) respuesta(s) del usuario, segun caso (submenu)
:caso: str (submenu)
"""
match caso:
case '/sethora':
user_ins = []
i = 0
for preg in diag_setdate[8:14]:
user_ins.append(valida_entrada(valid_dates[i], preg))
i += 1
return user_ins
case '/horasAcc':
user_ins = []
for preg in diag_settimer[10:14]:
user_ins.append(valida_entrada(valid_hrs_timer, preg))
return user_ins
case '/setservo':
user_ins = []
for preg in diag_posservo[10:14]:
user_ins += valida_entrada(valid_posicion, preg)
return user_ins
case '/accion':
return valida_entrada(valid_manual ,diag_accman[-1],'str')
case '/setlibre':
return valida_entrada(valid_posicion ,diag_servman[-1])
case _:
mensaje = ' Ingresa una opción \b\b\b\b\b\b:'
return valida_entrada(valid_opcs, mensaje, 'str')
def respuesta_config(respuesta):
"""Imprime el argumento formateado en el terminal bajo el contexto de
respuesta del ESP a alguna configuración.
:respuesta: str (mensaje de respuesta)
"""
print(col_resp + respuesta + col_rst)
def respuesta_info(caso='foo'):
"""Imprime en terminal bajo el contexto de respuesta informativa o
advertencia del ESP a alguna solicitud.
:caso: str (tipo de mensaje)
"""
match caso:
case 'error':
print(col_error + diag_volver[3] + col_rst)
sleep(1)
case 'volver':
print(col_error + diag_volver[2] + col_rst)
sleep(1)
case _:
print(col_error + diag_volver[1] + col_rst)
sleep(1)