""" Program to connect to KiwiSDR, collect signal sampling and to snr evaluation. Data is stored to RRD (round robin database) Use snrgraph to prepare graphs """ import numpy as np import struct import array import logging import socket import struct import time from datetime import datetime from suntime import Sun import pathlib import wsclient import mod_pywebsocket.common from mod_pywebsocket.stream import Stream from mod_pywebsocket.stream import StreamOptions from optparse import OptionParser import rrdtool parser = OptionParser() #parser.add_option("-f", "--file", dest="filename", type=str, # help="write waterfall data to binary FILE", metavar="FILE") parser.add_option("-s", "--server", type=str, help="server name", dest="server", default='192.168.0.164') parser.add_option("-p", "--port", type=int, help="port number", dest="port", default=8073) parser.add_option("-l", "--length", type=int, help="how many samples to draw from the server", dest="length", default=100) parser.add_option("-t", "--timestep", type=int, help="Expected timestep between samples", dest="step", default=300) parser.add_option("-z", "--zoom", type=int, help="zoom factor", dest="zoom", default=0) parser.add_option("-o", "--offset", type=int, help="start frequency in kHz", dest="start", default=0) parser.add_option("-v", "--verbose", type=int, help="whether to print progress and debug info", dest="verbosity", default=0) options = vars(parser.parse_args()[0]) if 'filename' in options: filename = options['filename'] else: filename = None host = options['server'] port = options['port'] print("KiwiSDR Server: %s:%d" % (host,port)) # the default number of bins is 1024 bins = 1024 print("Number of waterfall bins: %d" % bins) zoom = options['zoom'] print("Zoom factor:", zoom) offset_khz = options['start'] # this is offset in kHz full_span = 30000.0 # for a 30MHz kiwiSDR if zoom>0: span = int(full_span / 2.**zoom) else: span = int(full_span) rbw = span/bins if offset_khz>0: # offset = (offset_khz-span/2)/(full_span/bins)*2**(zoom)*1000. offset = (offset_khz+100)/(full_span/bins)*2**(4)*1000. offset = max(0, offset) else: offset = 0 center_freq = int(span/2+offset_khz) print("Start/End: %.2f / %.2f kHz" % (center_freq - span/2, center_freq + span/2)) snrname = f"{host}_{int(center_freq - span/2)}_{int(center_freq + span/2)}" snrfile = snrname + ".rrd" print("Current rrd file: ", snrfile) snrpath = pathlib.Path(snrfile) step = options['step'] #Seconds between samples #daystep = 2 * step #Daily graph stepsize #weekstep = 7 * daystep #Weekly graph stepsize #monthstep = 7 * weekstep #Monthly graph stepsize # Define RRD database if not done if not snrpath.is_file(): rrdtool.create( snrfile, #"--source", snrfile, #snrfile, remove comment and not if recreating #"--start", "now", #start time, uses default now - 10s "--step", str(step), #timestep, adjust crontab accordingly f"DS:median:GAUGE:{step*10}:-150:-40", #Expect readings every 10 step f"DS:p95:GAUGE:{step*10}:-150:-40", f"DS:snr:GAUGE:{step*10}:0:40", f"RRA:AVERAGE:0.5:5m:1d", #Daily data f"RRA:AVERAGE:0.5:30m:1w", #Weekly data f"RRA:MAX:0.1:1h:30d", #Monthly max f"RRA:MIN:0.1:1h:30d", #Monthly min f"RRA:LAST:0.5:1:1") #Last value now = str.encode(str(datetime.now())) header = [center_freq, span, now] #print("Header: ", center_freq, span, now) #header format; unsigned int (I), unsigned int (i), 26 char array header_bin = struct.pack("II26s", *header) print("Trying to contact server...") try: mysocket = socket.socket() mysocket.connect((host, port)) except: print("Failed to connect....exit") exit() print("Socket open...") uri = '/%d/%s' % (int(time.time()), 'W/F') handshake = wsclient.ClientHandshakeProcessor(mysocket, host, port) handshake.handshake(uri) request = wsclient.ClientRequest(mysocket) request.ws_version = mod_pywebsocket.common.VERSION_HYBI13 stream_option = StreamOptions() stream_option.mask_send = True stream_option.unmask_receive = False mystream = Stream(request, stream_option) print("Data stream active...") # send a sequence of messages to the server, hardcoded for now # max wf speed, no compression msg_list = ['SET auth t=kiwi p=', 'SET zoom=%d start=%d'%(zoom,offset),\ 'SET maxdb=0 mindb=-100', 'SET wf_speed=4', 'SET wf_comp=0'] for msg in msg_list: mystream.send_message(msg) print("Starting to retrieve waterfall data...") # number of samples to draw from server length = options['length'] # create a numpy array to contain the waterfall data wf_data = np.zeros((length, bins)) binary_wf_list = [] time = 0 while time