06-sep: [aspiradora] mapping MIoT real r2205 (bateria siid3) + menu reabre categoria tras consulta
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
"""Aspiradora Dreame D10 Plus (dreame.vacuum.r2205) via python-miio.
|
"""Aspiradora Dreame D10 Plus (dreame.vacuum.r2205) via python-miio.
|
||||||
|
|
||||||
El modelo r2205 habla el spec MIoT de mc1808, asi que se le pasa el
|
Usa el spec MIoT REAL del r2205 (NO el de mc1808: ahi la bateria esta en
|
||||||
mapping de mc1808 explicitamente. Lee IP/token del .env del directorio.
|
otro siid y por eso marcaba 2%). Lee IP/token del .env del directorio.
|
||||||
Uso: python aspiradora.py estado|start|stop|home|pause|locate
|
Uso: python aspiradora.py estado|start|stop|home|pause|locate
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
@@ -11,16 +11,33 @@ BASE = os.path.dirname(os.path.abspath(__file__))
|
|||||||
if BASE not in sys.path:
|
if BASE not in sys.path:
|
||||||
sys.path.insert(0, BASE)
|
sys.path.insert(0, BASE)
|
||||||
|
|
||||||
ESTADOS = {
|
# Spec https://home.miot-spec.com/spec/dreame.vacuum.r2205
|
||||||
1: "limpiando",
|
MAP_R2205 = {
|
||||||
2: "inactiva",
|
"battery_level": {"siid": 3, "piid": 1},
|
||||||
3: "pausada",
|
"charging_state": {"siid": 3, "piid": 2},
|
||||||
4: "error",
|
"device_fault": {"siid": 2, "piid": 2},
|
||||||
5: "volviendo a la base",
|
"device_status": {"siid": 2, "piid": 1},
|
||||||
6: "cargando",
|
"cleaning_mode": {"siid": 4, "piid": 4},
|
||||||
7: "actualizando",
|
"cleaning_time": {"siid": 4, "piid": 2},
|
||||||
|
"cleaning_area": {"siid": 4, "piid": 3},
|
||||||
|
"volume": {"siid": 7, "piid": 1},
|
||||||
|
"start_clean": {"siid": 2, "aiid": 1},
|
||||||
|
"stop_clean": {"siid": 4, "aiid": 2},
|
||||||
|
"pause": {"siid": 2, "aiid": 2},
|
||||||
|
"home": {"siid": 3, "aiid": 1},
|
||||||
|
"locate": {"siid": 7, "aiid": 1},
|
||||||
|
"play_sound": {"siid": 7, "aiid": 2},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ESTADOS = {
|
||||||
|
1: "limpiando", 2: "inactiva", 3: "pausada", 4: "error",
|
||||||
|
5: "volviendo a la base", 6: "cargando", 7: "fregando",
|
||||||
|
11: "creando mapa", 12: "limpieza de zona", 13: "carga completa",
|
||||||
|
14: "actualizando",
|
||||||
|
}
|
||||||
|
CARGAS = {1: "cargando", 2: "no cargando", 5: "volviendo a cargar"}
|
||||||
|
MODOS = {0: "silencioso", 1: "estándar", 2: "medio", 3: "fuerte"}
|
||||||
|
|
||||||
|
|
||||||
def _env(nombre, defecto=""):
|
def _env(nombre, defecto=""):
|
||||||
valor = os.getenv(nombre, defecto).strip()
|
valor = os.getenv(nombre, defecto).strip()
|
||||||
@@ -48,20 +65,26 @@ def conectar():
|
|||||||
token = _env("DREAME_TOKEN")
|
token = _env("DREAME_TOKEN")
|
||||||
if not token:
|
if not token:
|
||||||
raise RuntimeError("Falta DREAME_TOKEN en el .env")
|
raise RuntimeError("Falta DREAME_TOKEN en el .env")
|
||||||
return DreameVacuum(ip, token, model="dreame.vacuum.r2205",
|
# El mapping se resuelve por modelo: se registra el r2205 (spec real).
|
||||||
mapping=MIOT_MAPPING["dreame.vacuum.mc1808"])
|
MIOT_MAPPING.setdefault("dreame.vacuum.r2205", MAP_R2205)
|
||||||
|
return DreameVacuum(ip, token, model="dreame.vacuum.r2205")
|
||||||
|
|
||||||
|
|
||||||
def estado():
|
def estado():
|
||||||
vac = conectar()
|
vac = conectar()
|
||||||
st = vac.status()
|
d = vac.status().data
|
||||||
cod = st.device_status
|
cod = d.get("device_status")
|
||||||
texto_estado = ESTADOS.get(cod, f"codigo {cod}")
|
texto_estado = ESTADOS.get(cod, f"codigo {cod}")
|
||||||
|
carga = CARGAS.get(d.get("charging_state"),
|
||||||
|
f"codigo {d.get('charging_state')}")
|
||||||
|
modo = MODOS.get(d.get("cleaning_mode"), d.get("cleaning_mode"))
|
||||||
|
fallo = d.get("device_fault")
|
||||||
|
extra = "" if fallo in (0, None) else f"\n⚠️ Fallo: <b>{fallo}</b>"
|
||||||
return (f"🤖 Dreame D10 Plus: <b>{texto_estado}</b>\n"
|
return (f"🤖 Dreame D10 Plus: <b>{texto_estado}</b>\n"
|
||||||
f"🔋 Bateria: <b>{st.battery_level}%</b> "
|
f"🔋 Bateria: <b>{d.get('battery_level')}%</b> ({carga})\n"
|
||||||
f"({'cargando' if st.charging_state else 'no cargando'})\n"
|
f"🧹 Modo: {modo} | "
|
||||||
f"🧹 Modo: {st.cleaning_mode} | "
|
f"Tiempo: {d.get('cleaning_time')} min | "
|
||||||
f"Tiempo: {st.cleaning_time} | Area: {st.cleaning_area}")
|
f"Area: {d.get('cleaning_area')} m2{extra}")
|
||||||
|
|
||||||
|
|
||||||
def main(argv):
|
def main(argv):
|
||||||
@@ -83,10 +106,10 @@ def main(argv):
|
|||||||
vac.home()
|
vac.home()
|
||||||
print("Volviendo a la base.")
|
print("Volviendo a la base.")
|
||||||
elif cmd == "pause":
|
elif cmd == "pause":
|
||||||
vac.pause()
|
vac.call_action("pause")
|
||||||
print("Pausada.")
|
print("Pausada.")
|
||||||
elif cmd == "locate":
|
elif cmd == "locate":
|
||||||
vac.play_sound()
|
vac.call_action("play_sound")
|
||||||
print("Emitiendo sonido de localizacion.")
|
print("Emitiendo sonido de localizacion.")
|
||||||
else:
|
else:
|
||||||
print("Uso: aspiradora.py estado|start|stop|home|pause|locate")
|
print("Uso: aspiradora.py estado|start|stop|home|pause|locate")
|
||||||
|
|||||||
@@ -295,6 +295,29 @@ def _fin_accion(chat_id):
|
|||||||
_enviar_nuevo(chat_id, "✅ Hecho. Pulsa /menu para volver al menú.", None)
|
_enviar_nuevo(chat_id, "✅ Hecho. Pulsa /menu para volver al menú.", None)
|
||||||
|
|
||||||
|
|
||||||
|
def _reabrir(chat_id, message_id, categoria, comando):
|
||||||
|
"""Para consultas (estado, listar): ejecuta, borra los mensajes viejos
|
||||||
|
dejando solo el ultimo resultado y muestra de nuevo el menu de la
|
||||||
|
categoria (con su tecla de volver operativa)."""
|
||||||
|
import pi_bot
|
||||||
|
pi_bot.procesar(comando, chat_id)
|
||||||
|
try:
|
||||||
|
hist = pi_bot.historial_chat.get(chat_id, []) or []
|
||||||
|
for mid in hist[:-1]:
|
||||||
|
_borrar(chat_id, mid)
|
||||||
|
pi_bot.historial_chat[chat_id] = hist[-1:] if hist else []
|
||||||
|
ent = pi_bot.entrantes_chat.get(chat_id, []) or []
|
||||||
|
for mid in ent:
|
||||||
|
_borrar(chat_id, mid)
|
||||||
|
pi_bot.entrantes_chat[chat_id] = []
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
_borrar(chat_id, message_id)
|
||||||
|
teclado = _teclado_categoria(chat_id, categoria)
|
||||||
|
if teclado is not None:
|
||||||
|
_enviar_nuevo(chat_id, _header(categoria), teclado)
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------------- menu ----
|
# ----------------------------------------------------------------- menu ----
|
||||||
|
|
||||||
def enviar_menu(chat_id):
|
def enviar_menu(chat_id):
|
||||||
@@ -318,8 +341,8 @@ def _header(categoria):
|
|||||||
return nombres.get(categoria, "🧭 <b>Menú IDD</b>")
|
return nombres.get(categoria, "🧭 <b>Menú IDD</b>")
|
||||||
|
|
||||||
|
|
||||||
def _abrir_categoria(chat_id, message_id, categoria):
|
def _teclado_categoria(chat_id, categoria):
|
||||||
teclado = {
|
teclados = {
|
||||||
"videoclub": lambda: teclado_videoclub(chat_id),
|
"videoclub": lambda: teclado_videoclub(chat_id),
|
||||||
"nas": teclado_nas,
|
"nas": teclado_nas,
|
||||||
"tv": teclado_tv,
|
"tv": teclado_tv,
|
||||||
@@ -328,10 +351,15 @@ def _abrir_categoria(chat_id, message_id, categoria):
|
|||||||
"sistema": teclado_sistema,
|
"sistema": teclado_sistema,
|
||||||
"router": teclado_router,
|
"router": teclado_router,
|
||||||
}
|
}
|
||||||
fn = teclado.get(categoria)
|
fn = teclados.get(categoria)
|
||||||
if not fn:
|
return fn() if fn else None
|
||||||
|
|
||||||
|
|
||||||
|
def _abrir_categoria(chat_id, message_id, categoria):
|
||||||
|
teclado = _teclado_categoria(chat_id, categoria)
|
||||||
|
if teclado is None:
|
||||||
return False
|
return False
|
||||||
_enviar_edit(chat_id, message_id, _header(categoria), fn())
|
_enviar_edit(chat_id, message_id, _header(categoria), teclado)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@@ -460,18 +488,26 @@ def _ejecutar_accion(chat_id, message_id, partes):
|
|||||||
"qos": "qos estado",
|
"qos": "qos estado",
|
||||||
"limite": "limite listar",
|
"limite": "limite listar",
|
||||||
"seguridad": "seguridad estado",
|
"seguridad": "seguridad estado",
|
||||||
"parental_listar": "parental listar",
|
|
||||||
}
|
}
|
||||||
|
if accion == "parental_listar":
|
||||||
|
_reabrir(chat_id, message_id, "parental", "parental listar")
|
||||||
|
return
|
||||||
if accion in directos:
|
if accion in directos:
|
||||||
_disp(chat_id, message_id, directos[accion])
|
_disp(chat_id, message_id, directos[accion])
|
||||||
return
|
return
|
||||||
if accion == "termo":
|
if accion == "termo":
|
||||||
|
if sub == "estado":
|
||||||
|
_reabrir(chat_id, message_id, "domotica", "termo estado")
|
||||||
|
elif sub in ("on", "off"):
|
||||||
_disp(chat_id, message_id, f"termo {sub}")
|
_disp(chat_id, message_id, f"termo {sub}")
|
||||||
|
_fin_accion(chat_id)
|
||||||
return
|
return
|
||||||
if accion == "aspiradora":
|
if accion == "aspiradora":
|
||||||
if sub in ("estado", "start", "stop", "home", "pause", "locate"):
|
if sub in ("estado", "start", "stop", "home", "pause", "locate"):
|
||||||
|
if sub == "estado":
|
||||||
|
_reabrir(chat_id, message_id, "domotica", "aspiradora estado")
|
||||||
|
else:
|
||||||
_disp(chat_id, message_id, f"aspiradora {sub}")
|
_disp(chat_id, message_id, f"aspiradora {sub}")
|
||||||
if sub != "estado":
|
|
||||||
_fin_accion(chat_id)
|
_fin_accion(chat_id)
|
||||||
return
|
return
|
||||||
if accion == "tablets":
|
if accion == "tablets":
|
||||||
|
|||||||
Reference in New Issue
Block a user