From ae60105b4d77579ceadeb36b8776a1ac4a4363dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Otgaar?= Date: Wed, 8 Oct 2025 12:11:24 +0200 Subject: [PATCH] feat: send connection message when starting up issue: N25B-150 --- main.py | 83 ++++++++++++++++++++++++++++++++++------ src/__init__.pyc | Bin 0 -> 135 bytes src/audio_streaming.pyc | Bin 0 -> 3592 bytes state.py | 2 +- state.pyc | Bin 0 -> 2301 bytes 5 files changed, 73 insertions(+), 12 deletions(-) create mode 100644 src/__init__.pyc create mode 100644 src/audio_streaming.pyc create mode 100644 state.pyc diff --git a/main.py b/main.py index 097dfe1..ef1849a 100644 --- a/main.py +++ b/main.py @@ -1,18 +1,23 @@ import sys import logging -logging. +import argparse import zmq +import json +import logging +import hashlib +import socket +import time from src.audio_streaming import AudioStreaming from state import state +from urlparse import urlparse def say(session, message): tts = session.service("ALTextToSpeech") tts.say(message) - def listen_for_messages(session): context = zmq.Context() socket = context.socket(zmq.SUB) @@ -23,6 +28,25 @@ def listen_for_messages(session): poller.register(socket, zmq.POLLIN) logging.info("Listening for messages") + + # Let the CB know we're connected. + pub = context.socket(zmq.PUB) + pub.bind("tcp://*:5555") + + time.sleep(1) + print("Now attempting to send connection data to CB.") + connection_data = { + "event": "robot_connected", + "id": state.__getattribute__("id"), + "name": state.__getattribute__("name"), + "port": state.__getattribute__("port") + } + + connection_json = json.dumps(connection_data) + pub.send_string(connection_json) + print("Send data: ", connection_json) + + while not state.exit_event.is_set(): if not poller.poll(200): continue # At most 200 ms delay after CTRL+C # We now know there's a message waiting for us @@ -31,34 +55,71 @@ def listen_for_messages(session): if session: say(session, message) - def get_session(): if "--qi-url" not in sys.argv: logging.info("No Qi URL argument given. Running in stand-alone mode.") - return None + ip = resolve_local_ip() + port = -1 + return None, ip, port + + parser = argparse.ArgumentParser() + parser.add_argument("--qi-url", type=str, help="Qi URL argument") + parser.add_argument("--name", type=str, default="Robot without name", help="Optional robot name") + args = parser.parse_args() + + name = args.name + parsed = urlparse(args.qi_url) + ip = parsed.hostname + port = parsed.port + + # If URL uses localhost, get own ip instead + if ip in ("localhost", "127.0.0.1"): + ip = resolve_local_ip() try: import qi except ImportError: logging.info("Unable to import qi. Running in stand-alone mode.") - return None + return None, ip, port, name try: app = qi.Application() app.start() - return app.session + return app.session, ip, port, name except RuntimeError: logging.info("Unable to connect to the robot. Running in stand-alone mode.") - return None + return None, ip, port, name +def resolve_local_ip(): + """Return the actual local IP, not 127.0.0.1.""" + try: + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + s.connect(("8.8.8.8", 80)) # Use a public IP just to resolve interface + ip = s.getsockname()[0] + s.close() + return ip + except Exception as e: + logging.warning("Could not resolve local IP: {}".format(e)) + return "127.0.0.1" + def main(): - session = get_session() + session, ip, port, name = get_session() - audio_streamer = AudioStreaming() - audio_streamer.run() + # hash ip, port into id + id_source = "{}:{}".format(ip, port) + unique_id = hashlib.md5(id_source).hexdigest() - listen_for_messages(session) # Runs indefinitely, until CTRL+C + print("created unique id: ", unique_id) + + state.id = unique_id + state.port = port + state.ip = ip + state.name = name + + logging.info("Session ID: {} (from {})".format(unique_id, id_source)) + + listen_for_messages(session) if __name__ == "__main__": diff --git a/src/__init__.pyc b/src/__init__.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ef345bcf7bd8aed388270c41a80d5184feded7c8 GIT binary patch literal 135 zcmZSn%*!Qc_%tJ#0SXv_v;zp=h+_OJ>JhCTtQD=Q{d0#_9a%fnbE)srs!J+%=@CAtP+XD42*vnsP+aBhL!vKN ztE5LM9;J1M@)wnMsXN9m)b+-79WSmyVNsm)^oKNE#om_3u z=4Zq_Ca8OiPaF9kha|c|>qIz->(rejY!AMkd#LC-@1`gQJ4I^aF|CxGrbQ~tpOMuH z{J^hfWp_Ij$1FD|;Hl(q{Fa(<7ugZ^oDHpxcw5EblPi4s7p7gJuJ~XNK2+3Iw5wS1 z^&6WP$U5cj)30BrJvi180-WM2mv$Ydj9ohQ(7^{AZ_o;SwCB?1ChfZHuk|s?e`6is zd64c^Xls#dm3H^HSRfYghxwKdA$z?-`Hy5r*{W|8!7QAE=gP)ys^ECNPWdmSltT2L z&=zlRW2}^#xgrj7M}-Ir){@QI9iioBjm`gx{m{uWqrK4UCsCdaI$5ecn|VW{7ra{? z?cE87agyEf24Nodwbi+o7%xn{B!y4YNPAh^ySeoV6D@eYw!=KddoNBRyI@X2z_o0c z#@^1JCycyU-%BEG7R?ymoyGYghOJPY04yRXTjQ5kfgER6jPSqMWIj9!O&V4^a+^N@%$p} z4fWML&+;bo7Ao=2q z)7C%_20AYvgWk}b&6AeNqn2n97@O;`pQLve23z(-!5eazH)O-ZVPungC_*@Y9uqkY zbxh5wd8eu-RYSQLbJS3EHK9&8lWImqY=?uv&np;)J^f_aA?cT;R!ztx&&)_~4RMaW zEJbp(!(q>w|H{#4re)CPt5le=K@ zGpZtDHv2;Y#5seYAVvYKM^i+flaK{2A;F6lgJ!}6=q$x6zz3CaEGw!4HiIm;Xj)io z6=}}vvSEmG{aGAHX&k1nFQp+<2k96~D5SEC?zMfcXfZLsMD9RVXHtiA;B#+u>QbA zrd=v3MO5aHce5lta*Zd!_ghur~pKB3K)?+d6MP$KSG)?f!;j>Xi&=uvs9a$)a^#;M~p6FN@SQ zprL3b)mpSsPL6D#Q=f4~>R=FF>t&&R_kw(LD<5i~!PUnodV=0W$n`zooK#9;0s}$J zi2H&p0D>{%0QcH#P}Yx_6ZOzn1!bjlMC+)~+JBn`u+33tn63-&0{Mhx9NO?`D$VC! z{vIngkBI<|GwPI6MPIL}s{Bo;n(N|pQXO~ds<;#sU5PJ5K_IO$2>Mw(>|yJ_05<-s zJiW#f^FLHoR{sa`eU9^K3~7W_)u`4gwTfgGbO@6)2n=hmjE-i}zsg(P;jLj|A>sTq z+^i<9B6>`eq~6Zr!iDypXEY)Zo4enC$G^vy3e{Pt&wwnM;d7Uj6!7_`AOInH`5$5{ z{@{k4guP^27Z}3+kjU8tmsCzuB!z#TzrMhel!vs_p4I~)Kpu$)%X`-$$0PKn`0b-2 qbQifG4Kr^b`VD8wt(~Yo~Ur|mp zy4@=psT+Mjqkz(YY=b6HHs}|kYoZ@UO|nhijdu9{Fl@qC_7{Ewzk}`2$KKvXRM32j zLe~CWNMLa4>e3*W-&HapV`aI z8~f50{)}BMZROW^TUJc9v%V)66Rr)f0P88|`3S-jT@e{66K_x;)HGzffs|T`{4CDl z=RTB~Gj+o9>?fOgCc~gCtnXm6MIra)(Aj(v;*3PNPq6FH%7yKZ=Vev&mv#xTn?K8Z zCv(8;NHO2X`EfR9neg_#KVSa_88*CYlpfkH{;U3+1jADSnS{&|F9i z6SG6Vk#IbqUx{8R@-3RTMDEg+qU(UvR<(DlYI6W1%`*%+@W35Hev@-$*Bc&5S`vnK zv)IOc2!T}3k!J(|D#jYnyuqC%5JR>fxIM@dR1>A^)%o9rCNHN`Xe6UqF)1TX1Re#? z*2_&i8Q?rSF-FoKaW92fbjPgU!q6wTx)MDkm;ZIIa()ArJ63rnPh#2Hd2?ppBEnI>)o_ z$;a+V$V_|#N5qpZdWQwGIeL!;7dd(#qHZ%zbUB`5wt6OsF;k1czRJccZ-JN3G5pYP zo(mPN3ZE_PNmZ4V41=1q;+dP}zp^0u0GB_)a?Do>_SM7S0P;W`&~9)Tgwl3