diff --git a/sip-notifier/config.yaml b/sip-notifier/config.yaml index cbb1472..b392017 100644 --- a/sip-notifier/config.yaml +++ b/sip-notifier/config.yaml @@ -1,5 +1,5 @@ name: "SIP Voice Notifier" -version: "2.1.0" +version: "2.1.1" slug: "sip-notifier" description: "Send voice notifications via SIP phone calls" arch: diff --git a/sip-notifier/sip_service.py b/sip-notifier/sip_service.py index 0217c3c..88dc9e3 100644 --- a/sip-notifier/sip_service.py +++ b/sip-notifier/sip_service.py @@ -3,6 +3,7 @@ import json import logging import os +import socket import tempfile import time from urllib.parse import urlparse @@ -26,6 +27,21 @@ CONFIG = {} DEFAULT_SAMPLE_RATE = 8000 +def get_local_ip(): + """Get local IP address of the container.""" + try: + # Create a socket to determine the local IP + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + # Connect to an external address (doesn't actually send data) + s.connect(("8.8.8.8", 80)) + local_ip = s.getsockname()[0] + s.close() + return local_ip + except Exception as e: + _LOGGER.warning(f"Could not auto-detect IP: {e}, using 0.0.0.0") + return "0.0.0.0" + + def download_and_convert_audio(url: str) -> str: """Download and convert audio to WAV.""" parsed_url = urlparse(url) @@ -98,7 +114,12 @@ def place_sip_call(destination: str, audio_file: str, duration: int): sip_server = CONFIG['sip_server'] sip_password = CONFIG['sip_password'] - _LOGGER.info(f"Connecting to SIP server: {sip_server}") + # Get local IP + local_ip = get_local_ip() + + _LOGGER.info(f"Local IP: {local_ip}") + _LOGGER.info(f"SIP Server: {sip_server}") + _LOGGER.info(f"Calling: {destination}") try: # Create VoIP phone @@ -108,48 +129,54 @@ def place_sip_call(destination: str, audio_file: str, duration: int): sip_user, sip_password, callCallback=None, - myIP=None, + myIP=local_ip, sipPort=5060, rtpPortLow=10000, rtpPortHigh=20000 ) phone.start() - time.sleep(2) # Wait for registration + _LOGGER.info("SIP phone started, waiting for registration...") + time.sleep(3) # Wait for registration - _LOGGER.info(f"Calling: {destination}") + _LOGGER.info(f"Making call to: {destination}") # Make call call = phone.call(destination) # Wait for call to be answered - timeout = 10 + timeout = 15 elapsed = 0 while call.state != CallState.ANSWERED and elapsed < timeout: time.sleep(0.5) elapsed += 0.5 + if elapsed % 2 == 0: + _LOGGER.info(f"Waiting for answer... ({elapsed}s)") if call.state != CallState.ANSWERED: - _LOGGER.warning("Call not answered within timeout") + _LOGGER.warning(f"Call not answered within {timeout}s timeout") + _LOGGER.info(f"Final call state: {call.state}") call.hangup() phone.stop() return - _LOGGER.info("Call answered! Playing audio...") + _LOGGER.info("✅ Call answered! Playing audio...") # Transmit audio file call.write_audio(audio_file) # Keep call active - _LOGGER.info(f"Call active for {duration}s") + _LOGGER.info(f"Keeping call active for {duration}s...") time.sleep(duration) # Hangup _LOGGER.info("Hanging up...") call.hangup() + time.sleep(1) # Cleanup phone.stop() + _LOGGER.info("Call completed successfully") except Exception as e: _LOGGER.error(f"Call error: {e}", exc_info=True) @@ -192,10 +219,9 @@ def handle_send_notification(): temp_files.append(audio_file) # Place call - _LOGGER.info(f"Calling: {destination}") place_sip_call(destination, audio_file, duration) - return jsonify({'status': 'success'}), 200 + return jsonify({'status': 'success', 'message': 'Call completed'}), 200 finally: # Cleanup @@ -233,6 +259,7 @@ if __name__ == '__main__': _LOGGER.info("Using pyVoIP from git (latest version)") _LOGGER.info(f"SIP Server: {CONFIG.get('sip_server', 'not configured')}") _LOGGER.info(f"SIP User: {CONFIG.get('sip_user', 'not configured')}") + _LOGGER.info(f"Local IP: {get_local_ip()}") _LOGGER.info("") _LOGGER.info("To use this add-on, add configuration to configuration.yaml") _LOGGER.info("See add-on README for details")