2022-01-18 18:38:05 +00:00
#!/usr/bin/env python3
2022-11-19 08:51:48 +00:00
# class taken from darksidelemm
2022-01-18 18:38:05 +00:00
# rigctl - https://github.com/darksidelemm/rotctld-web-gui/blob/master/rotatorgui.py#L35
#
# modified and adjusted to FreeDATA needs by DJ2LS
2022-12-27 17:17:12 +00:00
import contextlib
2022-05-11 22:10:59 +00:00
import socket
import structlog
2022-12-12 11:28:52 +00:00
import threading
2022-05-09 01:27:24 +00:00
2022-05-26 01:23:30 +00:00
class radio :
2022-05-11 22:10:59 +00:00
""" rigctld (hamlib) communication class """
2022-05-26 01:23:30 +00:00
2022-06-01 00:35:35 +00:00
log = structlog . get_logger ( " radio (rigctld) " )
2022-05-26 01:23:30 +00:00
2022-01-18 18:38:05 +00:00
def __init__ ( self , hostname = " localhost " , port = 4532 , poll_rate = 5 , timeout = 5 ) :
2022-05-28 15:52:05 +00:00
""" Open a connection to rigctld, and test it for validity """
2023-01-04 07:33:25 +00:00
self . ptt_sock = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
self . data_sock = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
2022-03-06 16:23:04 +00:00
2023-01-04 07:33:25 +00:00
self . ptt_connected = False
self . data_connected = False
2022-01-18 18:38:05 +00:00
self . hostname = hostname
self . port = port
2022-01-24 21:01:01 +00:00
self . connection_attempts = 5
2022-01-18 18:38:05 +00:00
2022-11-19 08:51:48 +00:00
# class wide variable for some parameters
2022-11-19 09:05:17 +00:00
self . bandwidth = ' '
self . frequency = ' '
2022-11-19 08:51:48 +00:00
self . mode = ' '
2023-01-30 11:08:45 +00:00
self . alc = ' '
2023-01-30 11:31:34 +00:00
self . strength = ' '
2023-01-30 11:08:45 +00:00
self . rf = ' '
2022-11-19 08:51:48 +00:00
2022-05-26 01:23:30 +00:00
def open_rig (
2023-01-31 16:44:46 +00:00
self ,
rigctld_ip ,
2023-02-03 07:09:57 +00:00
rigctld_port
2022-05-26 01:23:30 +00:00
) :
2022-03-04 15:50:32 +00:00
"""
Args :
2022-05-09 00:41:49 +00:00
rigctld_ip :
rigctld_port :
2022-03-04 15:50:32 +00:00
Returns :
"""
2022-01-24 21:01:01 +00:00
self . hostname = rigctld_ip
2022-01-24 22:29:34 +00:00
self . port = int ( rigctld_port )
2022-05-26 01:23:30 +00:00
2023-01-31 16:44:46 +00:00
# _ptt_connect = self.ptt_connect()
# _data_connect = self.data_connect()
2023-01-04 07:33:25 +00:00
ptt_thread = threading . Thread ( target = self . ptt_connect , args = [ ] , daemon = True )
ptt_thread . start ( )
data_thread = threading . Thread ( target = self . data_connect , args = [ ] , daemon = True )
data_thread . start ( )
# wait some time
threading . Event ( ) . wait ( 0.5 )
2023-01-04 18:26:11 +00:00
if self . ptt_connected and self . data_connected :
2023-01-04 07:33:25 +00:00
self . log . debug ( " Rigctl DATA/PTT initialized " )
2022-01-24 21:01:01 +00:00
return True
2022-05-11 22:10:59 +00:00
2022-05-26 01:23:30 +00:00
self . log . error (
2022-12-01 07:56:21 +00:00
" [RIGCTLD] Can ' t connect! " , ip = self . hostname , port = self . port
2022-05-26 01:23:30 +00:00
)
2022-05-11 22:10:59 +00:00
return False
2022-05-09 00:41:49 +00:00
2023-01-04 07:33:25 +00:00
def ptt_connect ( self ) :
""" Connect to rigctld instance """
while True :
if not self . ptt_connected :
try :
self . ptt_connection = socket . create_connection ( ( self . hostname , self . port ) )
self . ptt_connected = True
self . log . info (
" [RIGCTLD] Connected PTT instance to rigctld! " , ip = self . hostname , port = self . port
)
except Exception as err :
# ConnectionRefusedError: [Errno 111] Connection refused
self . close_rig ( )
self . log . warning (
" [RIGCTLD] PTT Reconnect... " ,
ip = self . hostname ,
port = self . port ,
e = err ,
)
threading . Event ( ) . wait ( 0.5 )
def data_connect ( self ) :
2022-03-06 16:23:04 +00:00
""" Connect to rigctld instance """
2023-01-04 07:33:25 +00:00
while True :
if not self . data_connected :
try :
self . data_connection = socket . create_connection ( ( self . hostname , self . port ) )
self . data_connected = True
self . log . info (
" [RIGCTLD] Connected DATA instance to rigctld! " , ip = self . hostname , port = self . port
)
except Exception as err :
# ConnectionRefusedError: [Errno 111] Connection refused
self . close_rig ( )
self . log . warning (
" [RIGCTLD] DATA Reconnect... " ,
ip = self . hostname ,
port = self . port ,
e = err ,
)
threading . Event ( ) . wait ( 0.5 )
def close_rig ( self ) :
""" """
self . ptt_sock . close ( )
self . data_sock . close ( )
self . ptt_connected = False
self . data_connected = False
def send_ptt_command ( self , command , expect_answer ) - > bytes :
""" Send a command to the connected rotctld instance,
and return the return value .
Args :
command :
"""
if self . ptt_connected :
2022-01-24 21:01:01 +00:00
try :
2023-01-04 07:33:25 +00:00
self . ptt_connection . sendall ( command + b " \n " )
except Exception :
2022-05-26 01:23:30 +00:00
self . log . warning (
2023-01-04 07:33:25 +00:00
" [RIGCTLD] Command not executed! " ,
command = command ,
2022-05-26 01:23:30 +00:00
ip = self . hostname ,
port = self . port ,
)
2023-01-04 07:33:25 +00:00
self . ptt_connected = False
return b " "
2022-01-18 18:38:05 +00:00
2023-01-04 07:33:25 +00:00
def send_data_command ( self , command , expect_answer ) - > bytes :
2022-03-04 15:50:32 +00:00
""" Send a command to the connected rotctld instance,
2022-01-18 18:38:05 +00:00
and return the return value .
2022-03-04 15:50:32 +00:00
Args :
2022-05-09 00:41:49 +00:00
command :
2022-03-04 15:50:32 +00:00
2022-01-18 18:38:05 +00:00
"""
2023-01-04 07:33:25 +00:00
if self . data_connected :
2023-01-31 16:44:46 +00:00
self . data_connection . setblocking ( False )
2023-03-20 21:02:52 +00:00
#Allow a little more time for a response from rigctld before generating a timeout, seems to have no ill effects on a well behaving setup and fixes Issue #373
self . data_connection . settimeout ( 0.30 )
2022-01-24 21:01:01 +00:00
try :
2023-01-04 07:33:25 +00:00
self . data_connection . sendall ( command + b " \n " )
2023-01-31 16:44:46 +00:00
2022-05-26 01:23:30 +00:00
except Exception :
self . log . warning (
" [RIGCTLD] Command not executed! " ,
command = command ,
ip = self . hostname ,
port = self . port ,
)
2023-01-04 07:33:25 +00:00
self . data_connected = False
2022-01-18 18:38:05 +00:00
2022-01-24 21:01:01 +00:00
try :
2023-01-04 07:33:25 +00:00
# recv seems to be blocking so in case of ptt we don't need the response
2022-12-27 16:48:06 +00:00
# maybe this speeds things up and avoids blocking states
2023-01-31 16:44:46 +00:00
recv = True
data = b ' '
while recv :
try :
2023-02-14 21:02:30 +00:00
data = self . data_connection . recv ( 4800 )
2023-01-31 16:44:46 +00:00
except socket . timeout :
recv = False
return data
# return self.data_connection.recv(64) if expect_answer else True
2022-05-26 01:23:30 +00:00
except Exception :
self . log . warning (
" [RIGCTLD] No command response! " ,
command = command ,
ip = self . hostname ,
port = self . port ,
)
2023-01-04 07:33:25 +00:00
self . data_connected = False
2022-05-25 22:27:33 +00:00
return b " "
2022-11-18 12:08:37 +00:00
def get_status ( self ) :
""" """
2023-01-04 07:33:25 +00:00
return " connected " if self . data_connected and self . ptt_connected else " unknown/disconnected "
2022-11-19 09:11:08 +00:00
2023-01-30 11:08:45 +00:00
def get_level ( self ) :
try :
data = self . send_data_command ( b " l RF " , True )
data = data . split ( b " \n " )
rf = data [ 0 ] . decode ( " utf-8 " )
if ' RPRT ' not in rf :
try :
2023-01-31 16:44:46 +00:00
self . rf = str ( rf )
2023-01-30 11:08:45 +00:00
except ValueError :
self . rf = str ( rf )
return self . rf
except Exception :
return self . rf
2023-01-30 11:31:34 +00:00
def get_strength ( self ) :
2023-01-30 11:08:45 +00:00
try :
2023-01-30 11:31:34 +00:00
data = self . send_data_command ( b " l STRENGTH " , True )
2023-01-30 11:08:45 +00:00
data = data . split ( b " \n " )
2023-01-30 11:31:34 +00:00
strength = data [ 0 ] . decode ( " utf-8 " )
if ' RPRT ' not in strength :
2023-01-30 11:08:45 +00:00
try :
2023-01-30 11:31:34 +00:00
self . strength = str ( strength )
2023-01-30 11:08:45 +00:00
except ValueError :
2023-01-30 11:31:34 +00:00
self . strength = str ( strength )
2023-01-30 11:08:45 +00:00
2023-01-30 11:31:34 +00:00
return self . strength
2023-01-30 11:08:45 +00:00
except Exception :
2023-01-30 11:31:34 +00:00
return self . strength
2023-01-30 11:08:45 +00:00
def get_alc ( self ) :
try :
data = self . send_data_command ( b " l ALC " , True )
data = data . split ( b " \n " )
alc = data [ 0 ] . decode ( " utf-8 " )
if ' RPRT ' not in alc :
try :
2023-02-01 12:41:34 +00:00
alc = float ( alc )
2023-01-30 11:08:45 +00:00
except ValueError :
2023-02-01 12:47:24 +00:00
self . alc = 0.0
2023-01-30 11:08:45 +00:00
return self . alc
except Exception :
return self . alc
2022-01-18 18:38:05 +00:00
def get_mode ( self ) :
2022-03-04 15:50:32 +00:00
""" """
2022-01-24 21:01:01 +00:00
try :
2023-01-04 07:33:25 +00:00
data = self . send_data_command ( b " m " , True )
2022-05-26 01:23:30 +00:00
data = data . split ( b " \n " )
2022-11-19 09:14:59 +00:00
data = data [ 0 ] . decode ( " utf-8 " )
if ' RPRT ' not in data :
2022-12-27 16:57:04 +00:00
try :
data = int ( data )
except ValueError :
self . mode = str ( data )
2022-11-19 08:51:48 +00:00
2022-11-19 09:05:17 +00:00
return self . mode
2022-05-26 01:23:30 +00:00
except Exception :
2022-11-19 09:14:59 +00:00
return self . mode
2022-05-09 01:27:24 +00:00
2022-05-28 12:08:33 +00:00
def get_bandwidth ( self ) :
2022-03-04 15:50:32 +00:00
""" """
2022-01-24 21:01:01 +00:00
try :
2023-01-04 07:33:25 +00:00
data = self . send_data_command ( b " m " , True )
2022-05-26 01:23:30 +00:00
data = data . split ( b " \n " )
2022-11-19 09:14:59 +00:00
data = data [ 1 ] . decode ( " utf-8 " )
2022-11-19 08:51:48 +00:00
2022-12-27 17:17:12 +00:00
if ' RPRT ' not in data and data not in [ ' ' ] :
with contextlib . suppress ( ValueError ) :
2022-12-27 16:57:04 +00:00
self . bandwidth = int ( data )
2022-11-19 09:05:17 +00:00
return self . bandwidth
2022-05-26 01:23:30 +00:00
except Exception :
2022-11-19 09:14:59 +00:00
return self . bandwidth
2022-05-09 00:41:49 +00:00
2022-01-18 18:38:05 +00:00
def get_frequency ( self ) :
2022-03-04 15:50:32 +00:00
""" """
2022-01-24 21:01:01 +00:00
try :
2023-01-04 07:33:25 +00:00
data = self . send_data_command ( b " f " , True )
2022-11-19 09:05:17 +00:00
data = data . decode ( " utf-8 " )
2022-12-27 17:04:29 +00:00
if ' RPRT ' not in data and data not in [ 0 , ' 0 ' , ' ' ] :
2022-12-27 17:17:12 +00:00
with contextlib . suppress ( ValueError ) :
data = int ( data )
# make sure we have a frequency and not bandwidth
if data > = 10000 :
self . frequency = data
2022-11-19 09:05:17 +00:00
return self . frequency
2022-05-26 01:23:30 +00:00
except Exception :
2022-11-19 09:14:59 +00:00
return self . frequency
2022-05-09 00:41:49 +00:00
2022-01-18 18:38:05 +00:00
def get_ptt ( self ) :
2022-03-04 15:50:32 +00:00
""" """
2022-01-24 21:01:01 +00:00
try :
2023-02-05 13:18:22 +00:00
return self . send_data_command ( b " t " , True )
2022-05-26 01:23:30 +00:00
except Exception :
2022-01-24 21:01:01 +00:00
return False
2022-05-09 00:41:49 +00:00
2022-01-24 21:01:01 +00:00
def set_ptt ( self , state ) :
2022-03-04 15:50:32 +00:00
"""
Args :
2022-05-09 00:41:49 +00:00
state :
2022-03-04 15:50:32 +00:00
Returns :
"""
2022-01-24 21:01:01 +00:00
try :
if state :
2023-01-04 07:33:25 +00:00
self . send_ptt_command ( b " T 1 " , False )
2022-01-24 21:01:01 +00:00
else :
2023-01-04 07:33:25 +00:00
self . send_ptt_command ( b " T 0 " , False )
2022-05-09 00:41:49 +00:00
return state
2022-05-26 01:23:30 +00:00
except Exception :
2022-01-24 21:01:01 +00:00
return False
2023-01-04 18:26:11 +00:00
def set_frequency ( self , frequency ) :
"""
Args :
frequency :
Returns :
"""
try :
command = bytes ( f " F { frequency } " , " utf-8 " )
self . send_data_command ( command , False )
except Exception :
return False
2023-01-04 19:12:03 +00:00
def set_mode ( self , mode ) :
"""
Args :
mode :
Returns :
"""
try :
command = bytes ( f " M { mode } { self . bandwidth } " , " utf-8 " )
self . send_data_command ( command , False )
except Exception :
return False