diff --git a/vigilancia/aspiradora.py b/vigilancia/aspiradora.py
index c9172b7..a1aad3b 100644
--- a/vigilancia/aspiradora.py
+++ b/vigilancia/aspiradora.py
@@ -21,6 +21,21 @@ MAP_R2205 = {
"cleaning_time": {"siid": 4, "piid": 2},
"cleaning_area": {"siid": 4, "piid": 3},
"volume": {"siid": 7, "piid": 1},
+ "voice_id": {"siid": 7, "piid": 2},
+ "set_voice": {"siid": 7, "aiid": 4},
+ "auto_collect": {"siid": 15, "piid": 1},
+ "start_collect": {"siid": 15, "aiid": 1},
+ "first_clean_time": {"siid": 12, "piid": 1},
+ "total_clean_time": {"siid": 12, "piid": 2},
+ "total_clean_times": {"siid": 12, "piid": 3},
+ "total_clean_area": {"siid": 12, "piid": 4},
+ "brush_left_time": {"siid": 9, "piid": 1},
+ "brush_life_level": {"siid": 9, "piid": 2},
+ "brush_left_time2": {"siid": 10, "piid": 1},
+ "brush_life_level2": {"siid": 10, "piid": 2},
+ "filter_life_level": {"siid": 11, "piid": 1},
+ "filter_left_time": {"siid": 11, "piid": 2},
+ "mop_mode": {"siid": 4, "piid": 5},
"start_clean": {"siid": 2, "aiid": 1},
"stop_clean": {"siid": 4, "aiid": 2},
"pause": {"siid": 2, "aiid": 2},
@@ -37,6 +52,7 @@ ESTADOS = {
}
CARGAS = {1: "cargando", 2: "no cargando", 5: "volviendo a cargar"}
MODOS = {0: "silencioso", 1: "estándar", 2: "medio", 3: "fuerte"}
+AGUAS = {1: "bajo", 2: "medio", 3: "alto"}
def _env(nombre, defecto=""):
@@ -87,11 +103,53 @@ def estado():
f"Area: {d.get('cleaning_area')} m2{extra}")
+def _get(vac, nombre):
+ d = vac.status().data
+ return d.get(nombre)
+
+
+def stats():
+ vac = conectar()
+ d = vac.status().data
+ return (f"📊 Estadísticas Dreame\n"
+ f"Limpiezas totales: {d.get('total_clean_times')}\n"
+ f"Tiempo total: {d.get('total_clean_time')} min\n"
+ f"Area total: {d.get('total_clean_area')} m2")
+
+
+def consumibles():
+ vac = conectar()
+ d = vac.status().data
+ return (f"🔧 Consumibles\n"
+ f"Cepillo: {d.get('brush_life_level')}% "
+ f"({d.get('brush_left_time')}h restantes)\n"
+ f"Lateral: {d.get('brush_life_level2')}% "
+ f"({d.get('brush_left_time2')}h restantes)\n"
+ f"Filtro: {d.get('filter_life_level')}% "
+ f"({d.get('filter_left_time')}h restantes)")
+
+
+def auto_estado():
+ vac = conectar()
+ d = vac.status().data
+ return ("🗑️ Vaciado automático: "
+ f"{'ON' if d.get('auto_collect') else 'OFF'}")
+
+
+def voz_estado():
+ vac = conectar()
+ d = vac.status().data
+ return (f"🔊 Voz actual: {d.get('voice_id')} | "
+ f"Volumen: {d.get('volume')}")
+
+
def main(argv):
if len(argv) < 2:
- print("Uso: aspiradora.py estado|start|stop|home|pause|locate")
+ print("Uso: aspiradora.py estado|start|stop|home|pause|locate|"
+ "vaciar|auto|stats|consumibles|potencia|agua|voz")
return 1
cmd = argv[1].lower()
+ arg = argv[2] if len(argv) > 2 else ""
try:
vac = conectar()
if cmd == "estado":
@@ -111,8 +169,46 @@ def main(argv):
elif cmd == "locate":
vac.call_action("play_sound")
print("Emitiendo sonido de localizacion.")
+ elif cmd == "vaciar":
+ vac.call_action("start_collect")
+ print("Vaciando en la base.")
+ elif cmd == "auto":
+ if arg.lower() in ("on", "1"):
+ vac.set_property_by(15, 1, 1)
+ print("Vaciado automatico activado.")
+ elif arg.lower() in ("off", "0"):
+ vac.set_property_by(15, 1, 0)
+ print("Vaciado automatico desactivado.")
+ else:
+ print(auto_estado().replace("", "").replace("", ""))
+ elif cmd == "stats":
+ print(stats().replace("", "").replace("", ""))
+ elif cmd == "consumibles":
+ print(consumibles().replace("", "").replace("", ""))
+ elif cmd == "potencia":
+ if arg.isdigit() and int(arg) in MODOS:
+ vac.set_property_by(4, 4, int(arg))
+ print(f"Potencia: {MODOS[int(arg)]}.")
+ else:
+ d = vac.status().data
+ print(f"Potencia actual: {MODOS.get(d.get('cleaning_mode'))} "
+ f"(0-3).")
+ elif cmd == "agua":
+ if arg.isdigit() and int(arg) in AGUAS:
+ vac.set_property_by(4, 5, int(arg))
+ print(f"Agua: {AGUAS[int(arg)]}.")
+ else:
+ d = vac.status().data
+ print(f"Agua actual: {AGUAS.get(d.get('mop_mode'))} (1-3).")
+ elif cmd == "voz":
+ if arg:
+ vac.set_voice(arg)
+ print(f"Voz cambiada a {arg} (si el pack existe).")
+ else:
+ print(voz_estado().replace("", "").replace("", ""))
else:
- print("Uso: aspiradora.py estado|start|stop|home|pause|locate")
+ print("Uso: aspiradora.py estado|start|stop|home|pause|locate|"
+ "vaciar|auto|stats|consumibles|potencia|agua|voz")
return 1
except Exception as e:
print(f"ERROR: {e}")
diff --git a/vigilancia/menu_idd.py b/vigilancia/menu_idd.py
index cbf85df..23ce37d 100644
--- a/vigilancia/menu_idd.py
+++ b/vigilancia/menu_idd.py
@@ -130,10 +130,32 @@ def teclado_aspi():
_btn("⏸️ Pausar", PREFIJO + "acc:aspiradora:pause"),
_btn("🏠 A la base", PREFIJO + "acc:aspiradora:home"),
],
+ [
+ _btn("🗑️ Vaciar", PREFIJO + "acc:aspiradora:vaciar"),
+ _btn("📊 Stats", PREFIJO + "acc:aspiradora:stats"),
+ ],
+ [
+ _btn("⚡ Potencia…", PREFIJO + "cat:potencia"),
+ _btn("🔧 Consumibles", PREFIJO + "acc:aspiradora:consumibles"),
+ ],
[_btn("⬅️ Domótica", PREFIJO + "cat:domotica")],
])
+def teclado_potencia():
+ return _mk([
+ [
+ _btn("🔈 Silencioso", PREFIJO + "acc:potencia:0"),
+ _btn("🔉 Estándar", PREFIJO + "acc:potencia:1"),
+ ],
+ [
+ _btn("🔊 Medio", PREFIJO + "acc:potencia:2"),
+ _btn("📢 Fuerte", PREFIJO + "acc:potencia:3"),
+ ],
+ [_btn("⬅️ Aspiradora", PREFIJO + "cat:aspi")],
+ ])
+
+
def teclado_termo():
return _mk([
[
@@ -351,6 +373,7 @@ def _header(categoria):
"parental": "👪 Control parental",
"domotica": "🏠 Domótica",
"aspi": "🤖 Aspiradora",
+ "potencia": "⚡ Potencia aspiradora",
"termo": "🔌 Termo",
"sistema": "🛠️ Sistema",
"router": "📡 Router ASUS",
@@ -394,6 +417,7 @@ def _teclado_categoria(chat_id, categoria):
"parental": teclado_parental,
"domotica": teclado_domotica,
"aspi": teclado_aspi,
+ "potencia": teclado_potencia,
"termo": teclado_termo,
"sistema": teclado_sistema,
"router": teclado_router,
@@ -575,13 +599,18 @@ def _ejecutar_accion(chat_id, message_id, partes):
_fin_accion(chat_id, "termo")
return
if accion == "aspiradora":
- if sub in ("estado", "start", "stop", "home", "pause", "locate"):
- if sub == "estado":
- _reabrir(chat_id, message_id, "aspi", "aspiradora estado")
- else:
- pi_bot.procesar(f"aspiradora {sub}", chat_id)
- _cerrar_menu(chat_id, message_id)
- _fin_accion(chat_id, "aspi")
+ if sub in ("estado", "stats", "consumibles"):
+ _reabrir(chat_id, message_id, "aspi", f"aspiradora {sub}")
+ elif sub in ("start", "stop", "home", "pause", "locate", "vaciar"):
+ pi_bot.procesar(f"aspiradora {sub}", chat_id)
+ _cerrar_menu(chat_id, message_id)
+ _fin_accion(chat_id, "aspi")
+ return
+ if accion == "potencia":
+ if sub.isdigit() and int(sub) in (0, 1, 2, 3):
+ pi_bot.procesar(f"aspiradora potencia {sub}", chat_id)
+ _cerrar_menu(chat_id, message_id)
+ _fin_accion(chat_id, "aspi")
return
if accion == "tablets":
if sub in ("bloquear", "desbloquear"):
diff --git a/vigilancia/pi_bot.py b/vigilancia/pi_bot.py
index 598ba5b..ca82982 100644
--- a/vigilancia/pi_bot.py
+++ b/vigilancia/pi_bot.py
@@ -811,8 +811,8 @@ def procesar(texto, chat_id):
"10. termo on|off|estado — controla el enchufe Tapo\n"
" ✏️ Ej: /termo estado\n\n"
"━━━ 🏠 DOMÓTICA ━━━\n"
- "10b. aspiradora estado|start|stop|home|pause|locate — Dreame D10 Plus\n"
- " ✏️ Ej: /aspiradora estado\n\n"
+ "10b. aspiradora ... — Dreame D10 Plus\n"
+ " ✏️ Ej: /aspiradora estado, /aspiradora vaciar, /aspiradora stats, /aspiradora potencia 3, /aspiradora agua 2, /aspiradora voz\n\n"
"━━━ 📺 TV ━━━\n"
"11. tv <mensaje> — mensaje rápido a la tele\n"
" ✏️ Ej: /tv la cena está lista\n"
@@ -1028,11 +1028,18 @@ def procesar_novedades(chat_id):
def procesar_aspiradora(argumento, chat_id):
- """Comandos de la Dreame D10 Plus: estado|start|stop|home|pause|locate."""
- accion = (argumento or "estado").lower().strip()
- if accion not in ("estado", "start", "stop", "home", "pause", "locate"):
- enviar("Uso: /aspiradora estado|start|stop|home|pause|locate.",
- chat_id)
+ """Dreame D10 Plus: estado|start|stop|home|pause|locate|vaciar|
+ auto on|off|stats|consumibles|potencia 0-3|agua 1-3|voz [id]."""
+ partes = (argumento or "estado").lower().strip().split(None, 1)
+ accion = partes[0]
+ arg = partes[1].strip() if len(partes) > 1 else ""
+ validas = ("estado", "start", "stop", "home", "pause", "locate",
+ "vaciar", "auto", "stats", "consumibles", "potencia",
+ "agua", "voz")
+ if accion not in validas:
+ enviar("Uso: /aspiradora estado|start|stop|home|pause|locate|"
+ "vaciar|auto on|off|stats|consumibles|potencia 0-3|agua 1-3|"
+ "voz [id].", chat_id)
return
try:
import aspiradora
@@ -1043,6 +1050,14 @@ def procesar_aspiradora(argumento, chat_id):
try:
if accion == "estado":
enviar(aspiradora.estado(), chat_id)
+ elif accion == "stats":
+ enviar(aspiradora.stats(), chat_id)
+ elif accion == "consumibles":
+ enviar(aspiradora.consumibles(), chat_id)
+ elif accion == "auto" and not arg:
+ enviar(aspiradora.auto_estado(), chat_id)
+ elif accion == "voz" and not arg:
+ enviar(aspiradora.voz_estado(), chat_id)
else:
vac = aspiradora.conectar()
if accion == "start":
@@ -1055,12 +1070,44 @@ def procesar_aspiradora(argumento, chat_id):
vac.home()
enviar("🏠 Volviendo a la base.", chat_id)
elif accion == "pause":
- vac.pause()
+ vac.call_action("pause")
enviar("⏸️ Pausada.", chat_id)
elif accion == "locate":
- vac.play_sound()
+ vac.call_action("play_sound")
enviar("🔊 Emitiendo sonido de localización.", chat_id)
- log(f"ASPIRADORA {accion} ok")
+ elif accion == "vaciar":
+ vac.call_action("start_collect")
+ enviar("🗑️ Vaciando en la base.", chat_id)
+ elif accion == "auto":
+ if arg in ("on", "1"):
+ vac.set_property_by(15, 1, 1)
+ enviar("🗑️ Vaciado automático activado.", chat_id)
+ else:
+ vac.set_property_by(15, 1, 0)
+ enviar("🗑️ Vaciado automático desactivado.",
+ chat_id)
+ elif accion == "potencia":
+ if arg.isdigit() and int(arg) in aspiradora.MODOS:
+ vac.set_property_by(4, 4, int(arg))
+ enviar(f"⚡ Potencia: "
+ f"{aspiradora.MODOS[int(arg)]}.", chat_id)
+ else:
+ enviar("Uso: /aspiradora potencia 0-3 "
+ "(0 silencioso, 1 estándar, 2 medio, 3 fuerte).",
+ chat_id)
+ elif accion == "agua":
+ if arg.isdigit() and int(arg) in aspiradora.AGUAS:
+ vac.set_property_by(4, 5, int(arg))
+ enviar(f"💧 Agua: {aspiradora.AGUAS[int(arg)]}.",
+ chat_id)
+ else:
+ enviar("Uso: /aspiradora agua 1-3 "
+ "(1 bajo, 2 medio, 3 alto).", chat_id)
+ elif accion == "voz":
+ vac.set_voice(arg)
+ enviar(f"🔊 Voz cambiada a {arg} "
+ f"(si el pack existe).", chat_id)
+ log(f"ASPIRADORA {accion} {arg} ok")
except Exception as e:
log(f"aspiradora error: {e}")
enviar(f"❌ Error con la aspiradora: {e}", chat_id)