130 lines
3.5 KiB
Python
Executable File
130 lines
3.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import json
|
|
import os
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
import paho.mqtt.client as mqtt
|
|
|
|
|
|
def read_env(path=".env"):
|
|
env = {}
|
|
p = Path(path)
|
|
if not p.exists():
|
|
return env
|
|
|
|
for raw in p.read_text().splitlines():
|
|
line = raw.strip()
|
|
if not line or line.startswith("#") or "=" not in line:
|
|
continue
|
|
k, v = line.split("=", 1)
|
|
env[k.strip()] = v.strip().strip('"').strip("'")
|
|
return env
|
|
|
|
|
|
def utc_now():
|
|
return datetime.now(timezone.utc).isoformat(timespec="seconds").replace("+00:00", "Z")
|
|
|
|
|
|
def build_payload(machine_id, mode):
|
|
base = {
|
|
"machine_id": machine_id,
|
|
"ts": utc_now(),
|
|
"source": "odoo_simulator",
|
|
}
|
|
|
|
if mode == "loaded":
|
|
base.update({
|
|
"order_present": True,
|
|
"order_coherent": True,
|
|
"odoo_state": "ready",
|
|
"workorder_id": 1000,
|
|
"production_order": f"SIM-{machine_id}-OK",
|
|
"product": "Orden simulada correcta",
|
|
})
|
|
|
|
elif mode == "no_order":
|
|
base.update({
|
|
"order_present": False,
|
|
"order_coherent": False,
|
|
"odoo_state": "none",
|
|
"workorder_id": None,
|
|
"production_order": None,
|
|
"product": None,
|
|
})
|
|
|
|
elif mode == "bad":
|
|
base.update({
|
|
"order_present": True,
|
|
"order_coherent": False,
|
|
"odoo_state": "wrong_machine",
|
|
"workorder_id": 9999,
|
|
"production_order": f"SIM-{machine_id}-BAD",
|
|
"product": "Orden simulada incoherente",
|
|
"reason": "Orden asignada a otra máquina o estado no válido",
|
|
})
|
|
|
|
elif mode == "fault":
|
|
base.update({
|
|
"order_present": True,
|
|
"order_coherent": True,
|
|
"odoo_state": "ready",
|
|
"workorder_id": 1001,
|
|
"production_order": f"SIM-{machine_id}-FAULT",
|
|
"product": "Orden simulada con fallo máquina",
|
|
"force_machine_fault": True,
|
|
})
|
|
|
|
else:
|
|
raise SystemExit(f"Modo no reconocido: {mode}")
|
|
|
|
return base
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) != 3:
|
|
print("Uso:")
|
|
print(" python publish_order_state.py CORT-00 loaded")
|
|
print(" python publish_order_state.py CORT-00 no_order")
|
|
print(" python publish_order_state.py CORT-00 bad")
|
|
print(" python publish_order_state.py CORT-00 fault")
|
|
raise SystemExit(1)
|
|
|
|
machine_id = sys.argv[1]
|
|
mode = sys.argv[2]
|
|
|
|
env = read_env()
|
|
|
|
mqtt_host = env.get("MQTT_HOST", "127.0.0.1")
|
|
mqtt_port = int(env.get("MQTT_PORT", "1883"))
|
|
mqtt_user = env.get("MQTT_USERNAME") or env.get("MQTT_USER")
|
|
mqtt_password = env.get("MQTT_PASSWORD")
|
|
|
|
tenant = env.get("TENANT", "ucepsa")
|
|
site = env.get("SITE", "ucepsa_onpremise")
|
|
vertical = env.get("VERTICAL", "edge_oee")
|
|
|
|
topic = f"vertical/{tenant}/{site}/{vertical}/order_state/{machine_id}"
|
|
payload = build_payload(machine_id, mode)
|
|
|
|
client = mqtt.Client(client_id=f"order_state_sim_{machine_id}")
|
|
if mqtt_user:
|
|
client.username_pw_set(mqtt_user, mqtt_password)
|
|
|
|
client.connect(mqtt_host, mqtt_port, 60)
|
|
client.loop_start()
|
|
|
|
info = client.publish(topic, json.dumps(payload, separators=(",", ":")), qos=0, retain=True)
|
|
info.wait_for_publish(timeout=5)
|
|
|
|
client.loop_stop()
|
|
client.disconnect()
|
|
|
|
print(f"Publicado en {topic}")
|
|
print(json.dumps(payload, indent=2, ensure_ascii=False))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|