Esempio n. 1
0
    def __init__(self, data):
        # myutils.debug_hex(data)
        string_length, self.id_key = myutils.get_utf8_string(data)
        tmp = 4 + string_length
        # print("  id_key: {} (len:{})".format(self.id_key, string_length))

        self.new_id = myutils.get_boolean(data[tmp:])
        # print("  [*] new: {}".format(self.new_id))
        tmp += myutils.DataSize._boolean
        # print("  [*] new_id:{}".format(self.new_id))

        self.now_time = myutils.get_time(data[tmp:])
        tmp += myutils.DataSize._time
        # print("  [*] date:{}".format(self.now_time))

        self.snr = myutils.get_int32(data[tmp:])
        tmp += myutils.DataSize._int32
        # print("  [*] snr:{}".format(self.snr))

        self.delta_time = myutils.get_double(data[tmp:])
        tmp += myutils.DataSize._double
        # print("  [*] delta_time:{}".format(self.delta_time))

        # Something in here? Seems zero in the debug
        # myutils.debug_hex(data[tmp:])
        tmp += myutils.DataSize._uint32

        self.delta_freq = myutils.get_uint32(data[tmp:])
        tmp += myutils.DataSize._uint32
        # print("  [*] delta_freq:{}".format(self.delta_freq))

        self.drift = myutils.get_uint32(data[tmp:])
        tmp += myutils.DataSize._uint32
        # print("  [*] drift:{}".format(self.drift))

        string_length, self.callsign = myutils.get_utf8_string(data[tmp:])
        tmp += 4 + string_length
        # print("  [*] callsign:{}".format(self.callsign))

        string_length, self.grid = myutils.get_utf8_string(data[tmp:])
        tmp += 4 + string_length
        # print("  [*] grid:{}".format(self.grid))

        self.power = myutils.get_uint32(data[tmp:])
        # print("  [*] power:{}".format(self.power))

        self.dist = 0
        self.bearing = 0
        if (myutils.validate_callsign(self.callsign)):
            if (myutils.validate_locator(self.grid)):
                self.dist = locator.calculate_distance("io64", self.grid)
                self.bearing = locator.calculate_heading("io64", self.grid)
Esempio n. 2
0
    def __init__(self, data):
        # myutils.debug_hex(data)
        string_length, self.id_key = myutils.get_utf8_string(data)
        tmp = 4 + string_length
        # print("  id_key: {} (len:{})".format(self.id_key, string_length))

        self.new_id = myutils.get_boolean(data[tmp:])
        # print("  [*] new: {}".format(self.new_id))
        tmp += myutils.DataSize._boolean
        # print("  [*] new_id:{}".format(self.new_id))

        self.now_time = myutils.get_time(data[tmp:])
        tmp += myutils.DataSize._time
        # print("  [*] date:{}".format(self.now_time))

        self.snr = myutils.get_int32(data[tmp:])
        tmp += myutils.DataSize._int32
        # print("  [*] snr:{}".format(self.snr))

        self.delta_time = myutils.get_double(data[tmp:])
        tmp += myutils.DataSize._double
        # print("  [*] delta_time:{}".format(self.delta_time))

        # Something in here? Seems zero in the debug
        # myutils.debug_hex(data[tmp:])
        tmp += myutils.DataSize._uint32

        self.delta_freq = myutils.get_uint32(data[tmp:])
        tmp += myutils.DataSize._uint32
        # print("  [*] delta_freq:{}".format(self.delta_freq))

        self.drift = myutils.get_uint32(data[tmp:])
        tmp += myutils.DataSize._uint32
        # print("  [*] drift:{}".format(self.drift))

        string_length, self.callsign = myutils.get_utf8_string(data[tmp:])
        tmp += 4 + string_length
        # print("  [*] callsign:{}".format(self.callsign))

        string_length, self.grid = myutils.get_utf8_string(data[tmp:])
        tmp += 4 + string_length
        # print("  [*] grid:{}".format(self.grid))

        self.power = myutils.get_uint32(data[tmp:])
        # print("  [*] power:{}".format(self.power))

        self.dist = 0
        self.bearing = 0
        if (myutils.validate_callsign(self.callsign)):
            if (myutils.validate_locator(self.grid)):
                self.dist = locator.calculate_distance("io64", self.grid)
                self.bearing = locator.calculate_heading("io64", self.grid)
    def test_calculate_heading_edge_cases(self):

        assert abs(calculate_heading("JN48QM", "JN48QM") - 0 ) < 1
    def test_calculate_heading_normal_cases(self):

        assert abs(calculate_heading("JN48QM", "FN44AB") - 298) < 1
        assert abs(calculate_heading("FN44AB", "JN48QM") - 54) < 1
        assert abs(calculate_heading("JN48QM", "QF67bf") - 74) < 1
        assert abs(calculate_heading("QF67BF", "JN48QM") - 310) < 1
Esempio n. 5
0
async def qrzLookup(origcall, config):
    '''Lookup call @QRZ'''
    my_lookuplib = LookupLib(lookuptype="qrz",
                             username=config['qrz.com']['username'],
                             pwd=config['qrz.com']['password'])
    cic = Callinfo(my_lookuplib)
    origcall = origcall.upper()
    try:
        call = cic.get_homecall(origcall)
        lookup = await qrzRedisLookup(call)
    except ValueError:
        callsign = None
        lookup = {}
        #dict()
        print("Not Found")
        return {'origcallsign': origcall, 'callsign': callsign}
    if lookup is False:
        try:
            lookup = cic.get_all(call)
            callsign = lookup['callsign']
            redis.set('qrz' + call.upper(), json.dumps(lookup, default=str))
            redis.expire('qrz' + call.upper(), 2629743000)
            redis.sadd('qrzCALLS', call.upper())
            calls.append(call.upper())
        except ValueError:
            callsign = None
            lookup = {}
            #dict()
            print("Not Found")
            return {'origcallsign': origcall, 'callsign': callsign}
        except KeyError:
            callsign = call
            lookup = {}
            #dict()
            print("Not Found")
            return {'origcallsign': origcall, 'callsign': callsign}
    else:
        callsign = lookup['callsign']

    if callsign and 'aliases' in lookup:
        print(
            fg('blue') + '-=' + fg('turquoise_4') + attr('bold') + callsign +
            attr('reset') + fg('blue') + '=-' + attr('reset') + " (" +
            ','.join(lookup['aliases']) + ')')
    else:
        print(
            fg('blue') + '-=' + fg('turquoise_4') + attr('bold') + callsign +
            fg('blue') + '=-')

    print(fg('#884444') + attr('bold') + 'QTH: ', end="")

    await dictLookupAndPrint(lookup, '#a4a24f', 'fname', False)
    await dictLookupAndPrint(lookup, '#a4a24f', 'name', False, ", ")

    await dictLookupAndPrint(lookup, 'navajo_white_3', 'addr1', False, ", ")
    await dictLookupAndPrint(lookup, 'navajo_white_3', 'zipcode', False)
    await dictLookupAndPrint(lookup, 'navajo_white_3', 'addr2', False, ", ")
    await dictLookupAndPrint(lookup, 'navajo_white_3', 'country')

    print(fg('#884444') + attr('bold') + 'Grid square: ', end="")
    await dictLookupAndPrint(lookup, 'dark_sea_green_3b', 'locator', False)
    print(fg('#884444') + attr('bold') + 'Latitude: ', end="")
    latitude = await dictLookupAndPrint(lookup, 'dark_sea_green_3b',
                                        'latitude', False)
    print(fg('#884444') + attr('bold') + 'Longitude: ', end="")
    longitude = await dictLookupAndPrint(lookup, 'dark_sea_green_3b',
                                         'longitude')

    print(fg('#884444') + attr('bold') + 'CCode: ', end="")
    await dictLookupAndPrint(lookup, 'dark_sea_green_3b', 'ccode', False)
    print(fg('#884444') + attr('bold') + 'CQZone: ', end="")
    await dictLookupAndPrint(lookup, 'dark_sea_green_3b', 'cqz', False)
    print(fg('#884444') + attr('bold') + 'ITUZone: ', end="")
    await dictLookupAndPrint(lookup, 'dark_sea_green_3b', 'ituz')

    print(fg('#884444') + attr('bold') + 'QSL: ', end="")
    await dictLookupAndPrint(lookup, 'navajo_white_3', 'qslmgr', False)
    print(fg('#884444') + attr('bold') + 'eQSL: ', end="")
    await dictLookupAndPrint(lookup, 'navajo_white_3', 'eqsl', False)
    print(fg('#884444') + attr('bold') + 'lotw: ', end="")
    await dictLookupAndPrint(lookup, 'navajo_white_3', 'lotw')

    print(fg('#884444') + attr('bold') + 'E-Mail: ', end="")
    email = await dictLookupAndPrint(lookup, 'navajo_white_3', 'email', True)

    locator1 = latlong_to_locator(cfg['qth']['latitude'],
                                  cfg['qth']['longitude'])
    locator2 = latlong_to_locator(latitude, longitude)
    heading = calculate_heading(locator1, locator2)
    longpath = calculate_heading_longpath(locator1, locator2)

    print(fg('#884444') + attr('bold') + 'Heading: ', end="")
    print(fg('navajo_white_3') + "%.1f°" % heading, end="")

    print(fg('#884444') + attr('bold') + ' Longpath: ', end="")
    print(fg('navajo_white_3') + "%.1f°" % longpath, end="")

    print(attr('reset'))

    return {
        'origcallsign': origcall,
        'callsign': callsign,
        'email': email,
        'latitude': latitude,
        'longitude': longitude,
        'heading': heading,
        'longpath': longpath
    }
Esempio n. 6
0
def main():
    global out_log
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    # server_address = ('127.0.0.1', 2237)

    # sock.sendto('test message', config.server_address)

    sock.bind(config.server_address)

    # config.use_curses = True
    if config.use_curses:
        jt_curses = WsjtxCurses()

    # Exit py_wsjtx on WSJT-X exit
    # exit_on_wsjtxexit = False

    # Enable DXCC notify alerts
    # notify_alert = True
    if config.notify_alert:
        Notify.init("DX")
        if not popup_toast('Notifications enabled'):
            jt_curses.add_main_window('[!] Notification Error')

    # Publish mqtt messages, requires paho installed
    # config.use_mqtt = True
    # mqtt_server = "192.168.0.12"

    # Write all decodes to a log file
    config.log_decodes = False
    config.log_outfile = "/tmp/py_wsjtx.log"

    # Read existing log file
    log = WsjtxLog()
    log_info = "[*] Logfile found, {} entries read, {} stations.".format(
        log.entry_count, len(log.log_entries))
    if config.use_curses:
        jt_curses.add_main_window(log_info)
    else:
        print(log_info)

    current_band = ""
    state = {}

    if config.log_decodes:
        out_log = open(config.log_outfile, 'a', 0)
        out_log.write("Started Log at {}\n".format(datetime.datetime.now()))

    if config.use_mqtt:
        import paho.mqtt.client as paho
        mqtt_client = paho.Client()
        mqtt_client.connect(config.mqtt_server, keepalive=60)
        mqtt_client.loop_start()
        mqtt_client.publish("py_wsjtx/status",
                            "Started at {}".format(datetime.datetime.now()))

    # # Replay is PITA when testing
    # data, server = sock.recvfrom(1024)
    # p = header.create_header()
    # p += Replay.create_packet()
    # sock.sendto(p, server)

    try:
        while True:
            data, server = sock.recvfrom(1024)
            h = header(data[0:16])
            # print "data:", data
            packet_type = struct.unpack(">L", data[8:12])[0]

            # print("[*] packet_type:{}".format(packet_type))
            if packet_type == PacketType.Heartbeat:
                payload = Heartbeat(data[12:])
                if config.use_curses:
                    jt_curses.update_heartbeat(
                        datetime.datetime.now().strftime("%H:%M:%S"))
                else:
                    print("[*] Heartbeat [{}]".format(datetime.datetime.now()))

                if config.use_mqtt:
                    mqtt_msg = json.dumps({
                        "heartbeat":
                        datetime.datetime.now().strftime("%H:%M:%S")
                    })
                    mqtt_client.publish(
                        "py_wsjtx/{}/status".format(payload.id_key), mqtt_msg)

            elif packet_type == PacketType.Status:
                payload = StateChange(data[12:])

                # Set a per radio state
                state[payload.id_key] = {
                    'freq': payload.dial_freq,
                    'mode': payload.tx_mode,
                    'tx': payload.tx_enabled,
                    'band': log.get_band(str(payload.dial_freq / 1000 / 1000))
                }

                if config.use_mqtt:
                    mqtt_msg = json.dumps({
                        'status_frequency': payload.dial_freq,
                        'status_mode': payload.tx_mode,
                        'status_tx': payload.tx_enabled
                    })
                    mqtt_client.publish(
                        "py_wsjtx/{}/status".format(payload.id_key), mqtt_msg)

                if config.use_curses:
                    jt_curses.set_banner(payload.dial_freq, payload.tx_mode,
                                         payload.tx_enabled)
                else:
                    print(payload.do_print())

                current_band = log.get_band(
                    str(payload.dial_freq / 1000 / 1000))
                # print("[!] Current band: {}".format(current_band))

            elif packet_type == PacketType.Decode:
                # myutils.debug_packet(data)
                payload = Decode(data[12:])

                # Get current radio state or return ???
                # decode_mode = state.get(payload.id_key, {}).get('mode','???')
                decode_mode = "JT65" if payload.mode == '#' else "JT9"
                decode_band = state.get(payload.id_key, {}).get('band', '???')
                decode_dialfreq = state.get(payload.id_key,
                                            {}).get('freq', '???')

                if config.use_mqtt:
                    mqtt_msg = json.dumps({
                        'time':
                        payload.now_time,
                        'db':
                        str(payload.snr).rjust(2),
                        'dt':
                        payload.delta_time,
                        'dialfreq':
                        decode_dialfreq,
                        'freq':
                        str(payload.delta_freq).rjust(4),
                        'mode':
                        decode_mode,
                        'band':
                        decode_band,
                        'msg':
                        payload.message
                    })
                    mqtt_client.publish(
                        "py_wsjtx/{}/decodes".format(payload.id_key), mqtt_msg)

                # info = "[{}] db:{:0>2} DT:{:.1f} Freq:{} DFreq:{} Mode:{} Msg: {}".format(
                #         payload.now_time,
                #         str(payload.snr).rjust(2),
                #         payload.delta_time,
                #         decode_dialfreq,
                #         str(payload.delta_freq).rjust(4),
                #         decode_mode,
                #         payload.message)

                info = "[{}] {:>3}db, {:>4}Hz, {:>3}, {:>4}, Msg: {}".format(
                    payload.now_time,
                    str(payload.snr).rjust(2),
                    str(payload.delta_freq).rjust(4), decode_band, decode_mode,
                    payload.message)

                if config.log_decodes:
                    out_log.write("{}\n".format(info))

                if config.use_curses:
                    jt_curses.add_main_window(info)
                else:
                    payload.do_print()

                # Check for CQ call
                if payload.message[:2] == "CQ":
                    cq = payload.message.split(" ")
                    if len(cq) > 1:
                        # CQ call should be 'CQ CALL LOC', but can be:
                        # 'CQ DX CALL LOC' or
                        # 'CQ CALL DX LOC'
                        cq_call = cq[1]
                        if len(cq) == 2:
                            cq_loc = ""
                        else:
                            cq_loc = cq[2]

                        if cq_call == "DX":
                            cq_call = cq[2]
                            if len(cq) > 3:
                                cq_loc = cq[3]
                            else:
                                cq_loc = ""

                        if cq_loc == "DX":
                            if len(cq) > 3:
                                cq_loc = cq[3]
                            else:
                                cq_loc = ""

                        # Check for valid callsign
                        if (myutils.validate_callsign(cq_call)):

                            # Have we worked call before?
                            band = log.check_entry2(cq_call, current_band)

                            if band["call"]:
                                # worked call before
                                if band["call_band"]:
                                    # ...and worked call on this band
                                    colour = bcolors.WKD_BEFORE
                                    status = log.WORKED_COUNTRY_AND_STATION

                                elif band["country_band"]:
                                    # Worked call on a different band but
                                    # also worked country on this band
                                    colour = bcolors.WKD_COUNTRY_NOT_STATION
                                    status = log.WORKED_COUNTRY_NOT_STATION

                                else:
                                    # TODO: check flags
                                    colour = bcolors.WKD_COUNTRY_DIFF_BAND
                                    status = log.WORKED_COUNTRY_DIFF_BAND

                            else:
                                # call not worked
                                if band["country"]:
                                    if band["country_band"]:
                                        # ...but have worked country on this band
                                        colour = bcolors.WKD_COUNTRY_NOT_STATION
                                        status = log.WORKED_COUNTRY_NOT_STATION

                                    else:
                                        # ...but have worked country before, on different band
                                        colour = bcolors.WKD_COUNTRY_DIFF_BAND
                                        status = log.WORKED_COUNTRY_DIFF_BAND

                                else:
                                    # Call or country not worked, raise DXCC alert
                                    colour = bcolors.NOT_WORKED
                                    status = log.NOT_WORKED

                                    if config.notify_alert:
                                        if not popup_toast(
                                                log.dxcc.find_country(
                                                    cq_call)):
                                            jt_curses.add_main_window(
                                                '[!] Failed to notify CQ')

                                    if config.use_mqtt:
                                        mqtt_msg = json.dumps({
                                            'time':
                                            payload.now_time,
                                            'db':
                                            str(payload.snr),
                                            'dxcc_call':
                                            cq_call,
                                            'dxcc_locator':
                                            cq_loc,
                                            'dxcc_country':
                                            log.dxcc.find_country(cq_call),
                                            'dxcc_mode':
                                            decode_mode,
                                            'dxcc_band':
                                            decode_band,
                                            'dialfreq':
                                            decode_dialfreq
                                        })
                                        mqtt_client.publish(
                                            "py_wsjtx/{}/dxcc".format(
                                                payload.id_key), mqtt_msg)

                            # Now display
                            if config.use_curses:
                                jt_curses.add_cq(
                                    cq_call, status + 1, cq_loc,
                                    log.dxcc.find_country(cq_call), band)
                            else:
                                print("[***] CQ CALLED BY {}{}{} ({}) [{}]".
                                      format(colour, cq_call, bcolors.ENDC,
                                             cq_loc, status))
                                if (myutils.validate_locator(cq_loc)):
                                    print(
                                        "  [*] Distance: {:.0f}km, Bearing:{:.0f}"
                                        .format(
                                            locator.calculate_distance(
                                                config.locator, cq_loc),
                                            locator.calculate_heading(
                                                config.locator, cq_loc)))

                        else:
                            msg = "[*] CQ by non-valid callsign?"
                            if config.use_curses:
                                jt_curses.add_main_window(msg)
                            else:
                                print(msg)

            elif packet_type == PacketType.Clear:
                payload = Clear(data[12:])
                if config.use_curses:
                    jt_curses.add_main_window("[*] Clear Called")
                else:
                    payload.do_print()

            elif packet_type == PacketType.Reply:
                # Not used, this is an out message
                pass

            elif packet_type == PacketType.QSO_Logged:
                # myutils.debug_packet(data)
                payload = Qso_Logged(data[12:])
                if config.use_curses:
                    jt_curses.add_main_window("[*] Logged QSO with {}".format(
                        payload.dx_call))
                else:
                    payload.do_print()
                # re-read the log file
                log.read_log()

            elif packet_type == PacketType.Close:
                payload = Close(data[12:])
                if config.use_curses:
                    jt_curses.add_main_window("[!] Exit called")
                else:
                    payload.do_print
                if config.exit_on_wsjtxexit:
                    sys.exit(0)

            elif packet_type == PacketType.Replay:
                # Not used, this is an out message
                pass

            elif packet_type == PacketType.Halt_TX:
                # Not used, this is an out message
                pass

            elif packet_type == PacketType.Free_Text:
                # Not used, this is an out message
                pass

            elif packet_type == PacketType.WSPRDecode:
                payload = WSPRDecode(data[12:])

                decode_band = state.get(payload.id_key, {}).get('band', '???')

                if config.use_mqtt:
                    mqtt_msg = json.dumps({
                        'WSPR_call': payload.callsign,
                        'band': decode_band,
                        'grid': payload.grid,
                        'dist': int(payload.dist),
                        'pwr': payload.power,
                        'db': payload.snr
                    })
                    mqtt_client.publish(
                        "py_wsjtx/{}/wspr".format(payload.id_key), mqtt_msg)

                info = "WSPR [{}]: {:10} ({:6}) db:{:4}, Freq:{:>10,}Hz, pwr:{:4}, Dist:{:>5.0f}km, Az: {:>3.0f}".format(
                    payload.now_time, payload.callsign, payload.grid,
                    payload.snr, payload.delta_freq, payload.power,
                    payload.dist, payload.bearing)

                if config.log_decodes:
                    out_log.write("{}\n".format(info))

                if config.use_curses:
                    jt_curses.add_main_window(info)
                else:
                    payload.do_print()

            else:
                if config.use_curses:
                    jt_curses.add_main_window(
                        "[*] Packet type: {}".format(packet_type))
                else:
                    print("[*] Packet type: {}".format(packet_type))

    except KeyboardInterrupt:
        if config.use_curses:
            jt_curses.exit_now()
        if config.log_decodes:
            out_log.write("Closed Log at {}\n".format(datetime.datetime.now()))
            out_log.close()
        print("ctrl-c caught, exiting")
        if config.notify_alert:
            Notify.uninit()
Esempio n. 7
0
            wspr_call = re.sub('[<>]', '', wspr_msg_split[0])
            wspr_loc = wspr_msg_split[1]
            wspr_pwr = wspr_msg_split[2]
            if (len(wspr_msg_split) != 4):
                print 'No correct wspr message.'

            band_vec = ('LF', 'MW', '160m', '80m', '60m', '40m', '30m', '20m',
                        '17m', '15m', '12m', '10m')
            freq_vec = (0.1, 0.4, 1.8, 3.5, 5.2, 7.0, 10.1, 14.0, 18.1, 21.0,
                        24.9, 28.1)
            wspr_band = band_vec[freq_vec.index(
                round(float(wspr_freq) - 0.05, 1))]

            wspr_dist = str(
                int(calculate_distance(wspr_loc_reporter, wspr_loc)))
            wspr_az = str(int(calculate_heading(wspr_loc_reporter, wspr_loc)))

            latitude, longitude = locator_to_latlong(wspr_loc)
            wspr_loc_geohash = geohash.encode(latitude, longitude, precision=5)

            print wspr_date + '' + wspr_time
            wspr_tuple_time = strptime(wspr_date + wspr_time, "%y%m%d%H%M")
            wspr_time = strftime("%Y-%m-%dT%H:%M:%SZ", wspr_tuple_time)
            print wspr_time

            json_body = [{
                "measurement": "wspr_redpitaya_test",
                "tags": {
                    "band": wspr_band,
                    "reporter": wspr_reporter,
                    "loc_reporter": wspr_loc_reporter,
Esempio n. 8
0
def main():
    global out_log
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    # server_address = ('127.0.0.1', 2237)

    # sock.sendto('test message', config.server_address)

    sock.bind(config.server_address)

    # config.use_curses = True
    if config.use_curses:
        jt_curses = WsjtxCurses()

    # Exit py_wsjtx on WSJT-X exit
    # exit_on_wsjtxexit = False

    # Enable DXCC notify alerts
    # notify_alert = True
    if config.notify_alert:
        Notify.init("DX")
        if not popup_toast('Notifications enabled'):
            jt_curses.add_main_window('[!] Notification Error')

    # Publish mqtt messages, requires paho installed
    # config.use_mqtt = True
    # mqtt_server = "192.168.0.12"

    # Write all decodes to a log file
    config.log_decodes = False
    config.log_outfile = "/tmp/py_wsjtx.log"

    # Read existing log file
    log = WsjtxLog()
    log_info = "[*] Logfile found, {} entries read, {} stations.".format(log.entry_count, len(log.log_entries))
    if config.use_curses:
        jt_curses.add_main_window(log_info)
    else:
        print(log_info)

    current_band = ""
    state = {}

    if config.log_decodes:
        out_log = open(config.log_outfile, 'a', 0)
        out_log.write("Started Log at {}\n".format(datetime.datetime.now()))

    if config.use_mqtt:
        import paho.mqtt.client as paho
        mqtt_client=paho.Client(protocol=paho.MQTTv31)
        mqtt_client.connect(config.mqtt_server, keepalive=60, )
        mqtt_client.loop_start()
        mqtt_client.publish("py_wsjtx/status", "Started at {}".format(datetime.datetime.now()))


    # # Replay is PITA when testing
    # data, server = sock.recvfrom(1024)
    # p = header.create_header()
    # p += Replay.create_packet()
    # sock.sendto(p, server)

    try:
        while True:
            data, server = sock.recvfrom(1024)
            h = header(data[0:16])
            # print "data:", data
            packet_type = struct.unpack(">L", data[8:12])[0]

            # print("[*] packet_type:{}".format(packet_type))
            if packet_type == PacketType.Heartbeat:
                payload = Heartbeat(data[12:])
                if config.use_curses:
                    jt_curses.update_heartbeat(datetime.datetime.now().strftime("%H:%M:%S"))
                else:
                    print("[*] Heartbeat [{}]".format(datetime.datetime.now()))

                if config.use_mqtt:
                    mqtt_msg = json.dumps({"heartbeat": datetime.datetime.now().strftime("%H:%M:%S")})
                    mqtt_client.publish("py_wsjtx/{}/status".format(payload.id_key), mqtt_msg)

            elif packet_type == PacketType.Status:
                payload = StateChange(data[12:])

                # Set a per radio state
                state[payload.id_key] = {'freq': payload.dial_freq,
                                        'mode': payload.tx_mode,
                                        'tx': str(payload.tx_enabled),
                                        'band': log.get_band(str(payload.dial_freq/1000/1000))
                                        }

                if config.use_mqtt:
                    mqtt_msg = json.dumps({'status_frequency': str(payload.dial_freq),
                                        'status_mode': str(payload.tx_mode),
                                        'status_tx': str(payload.tx_enabled)})
                    mqtt_client.publish("py_wsjtx/{}/status".format(payload.id_key), mqtt_msg)

                if config.use_curses:
                    jt_curses.set_banner(payload.dial_freq,
                                         payload.tx_mode,
                                         str(payload.tx_enabled))
                else:
                    print(payload.do_print())

                current_band = log.get_band(str(payload.dial_freq/1000/1000))
                # print("[!] Current band: {}".format(current_band))

            elif packet_type == PacketType.Decode:
                # myutils.debug_packet(data)
                payload = Decode(data[12:])

                # Get current radio state or return ???
                decode_mode = state.get(payload.id_key, {}).get('mode','???')

                # If it's JT65/JT9 mode, check actual received signal mode
                if decode_mode == "JT9" or decode_mode == "JT65":
                    if payload.mode == '#':
                        decode_mode = "JT65"
                    elif payload.mode == "@":
                        decode_mode = "JT9"
                    else:
                        decode_mode = "ERR"

                decode_band = state.get(payload.id_key, {}).get('band','???')
                decode_dialfreq = state.get(payload.id_key, {}).get('freq','???')

                if config.use_mqtt:
                    mqtt_msg = json.dumps({'time': payload.now_time,
                                        'db': str(payload.snr).rjust(2),
                                        'dt': payload.delta_time,
                                        'dialfreq': decode_dialfreq,
                                        'freq': str(payload.delta_freq).rjust(4),
                                        'mode': decode_mode,
                                        'band': decode_band,
                                        'msg': payload.message})
                    # mqtt_client.publish("py_wsjtx/{}/decodes".format(payload.id_key), mqtt_msg)
                    mqtt_client.publish("py_wsjtx/{}/decodes".format("WSJT-X"), mqtt_msg)


                # info = "[{}] db:{:0>2} DT:{:.1f} Freq:{} DFreq:{} Mode:{} Msg: {}".format(
                #         payload.now_time,
                #         str(payload.snr).rjust(2),
                #         payload.delta_time,
                #         decode_dialfreq,
                #         str(payload.delta_freq).rjust(4),
                #         decode_mode,
                #         payload.message)

                info = "[{}] {:>3}db, {:>4}Hz, {:>3}, {:>4}, Msg: {}".format(
                        payload.now_time,
                        str(payload.snr).rjust(2),
                        str(payload.delta_freq).rjust(4),
                        decode_band,
                        decode_mode,
                        payload.message
                )

                if config.log_decodes:
                    out_log.write("{}\n".format(info))

                if config.use_curses:
                    jt_curses.add_main_window(info)
                else:
                    payload.do_print()

                # Check for CQ call
                if payload.message[:2] == "CQ":
                    cq = payload.message.split(" ")
                    if len(cq) > 1:
                        # CQ call should be 'CQ CALL LOC', but can be:
                        # 'CQ DX CALL LOC' or
                        # 'CQ CALL DX LOC'
                        try:
                            cq_call = cq[1]
                            if len(cq) == 2:
                                cq_loc = ""
                            else:
                                cq_loc = cq[2]

                            if cq_call == "DX":
                                cq_call = cq[2]
                                if len(cq) > 3:
                                    cq_loc = cq[3]
                                else:
                                    cq_loc = ""

                            if cq_loc == "DX":
                                if len(cq) > 3:
                                    cq_loc = cq[3]
                                else:
                                    cq_loc = ""
                        except:
                            print("[!] Error parsing CQ call")
                            continue

                        # Check for valid callsign
                        if (myutils.validate_callsign(cq_call)):

                            # Have we worked call before?
                            band = log.check_entry2(cq_call, current_band)

                            if band["call"]:
                                # worked call before
                                if band["call_band"]:
                                    # ...and worked call on this band
                                    colour = bcolors.WKD_BEFORE
                                    status = log.WORKED_COUNTRY_AND_STATION

                                elif band["country_band"]:
                                    # Worked call on a different band but 
                                    # also worked country on this band
                                    colour = bcolors.WKD_COUNTRY_NOT_STATION
                                    status = log.WORKED_COUNTRY_NOT_STATION

                                else:
                                    # TODO: check flags
                                    colour = bcolors.WKD_COUNTRY_DIFF_BAND
                                    status = log.WORKED_COUNTRY_DIFF_BAND

                            else:
                                # call not workedg
                                if band["country"]:
                                    if band["country_band"]:
                                        # ...but have worked country on this band
                                        colour = bcolors.WKD_COUNTRY_NOT_STATION
                                        status = log.WORKED_COUNTRY_NOT_STATION

                                    else:
                                        # ...but have worked country before, on different band
                                        colour = bcolors.WKD_COUNTRY_DIFF_BAND
                                        status = log.WORKED_COUNTRY_DIFF_BAND

                                else:
                                    # Call or country not worked, raise DXCC alert
                                    colour = bcolors.NOT_WORKED
                                    status = log.NOT_WORKED

                                    if config.notify_alert:
                                        if not popup_toast(log.dxcc.find_country(cq_call)):
                                            jt_curses.add_main_window('[!] Failed to notify CQ')

                                    if config.use_mqtt:
                                        mqtt_msg = json.dumps({'time': payload.now_time,
                                                        'db': str(payload.snr),
                                                        'dxcc_call': cq_call,
                                                        'dxcc_locator': cq_loc,
                                                        'dxcc_country': log.dxcc.find_country(cq_call),
                                                        'dxcc_mode': decode_mode,
                                                        'dxcc_band': decode_band,
                                                        'dialfreq': decode_dialfreq})
                                        mqtt_client.publish("py_wsjtx/{}/dxcc".format(payload.id_key), mqtt_msg)

                            # Now display
                            if config.use_curses:
                                jt_curses.add_cq(cq_call,
                                                status+1,
                                                cq_loc,
                                                log.dxcc.find_country(cq_call),
                                                band)
                            else:
                                print("[***] CQ CALLED BY {}{}{} ({}) [{}]".format(colour, cq_call, bcolors.ENDC, cq_loc, status))
                                if (myutils.validate_locator(cq_loc)):
                                    print("  [*] Distance: {:.0f}km, Bearing:{:.0f}".format(
                                            locator.calculate_distance(config.locator, cq_loc),
                                            locator.calculate_heading(config.locator, cq_loc)
                                        ))

                        else:
                            msg = "[*] CQ by non-valid callsign?"
                            if config.use_curses:
                                jt_curses.add_main_window(msg)
                            else:
                                print(msg)

            elif packet_type == PacketType.Clear:
                payload = Clear(data[12:])
                if config.use_curses:
                    jt_curses.add_main_window("[*] Clear Called")
                else:
                    payload.do_print()

            elif packet_type == PacketType.Reply:
                # Not used, this is an out message
                pass

            elif packet_type == PacketType.QSO_Logged:
                # myutils.debug_packet(data)
                payload = Qso_Logged(data[12:])
                if config.use_curses:
                    jt_curses.add_main_window("[*] Logged QSO with {}".format(payload.dx_call))
                else:
                    payload.do_print()
                # re-read the log file
                log.read_log()

            elif packet_type == PacketType.Close:
                payload = Close(data[12:])
                if config.use_curses:
                    jt_curses.add_main_window("[!] Exit called")
                else:
                    payload.do_print
                if config.exit_on_wsjtxexit:
                    sys.exit(0)

            elif packet_type == PacketType.Replay:
                # Not used, this is an out message
                pass

            elif packet_type == PacketType.Halt_TX:
                # Not used, this is an out message
                pass

            elif packet_type == PacketType.Free_Text:
                # Not used, this is an out message
                pass

            elif packet_type == PacketType.WSPRDecode:
                payload = WSPRDecode(data[12:])

                decode_band = state.get(payload.id_key, {}).get('band','???')

                if config.use_mqtt:
                    mqtt_msg = json.dumps({'WSPR_call': payload.callsign,
                                        'band': decode_band,
                                        'grid': payload.grid,
                                        'dist': int(payload.dist),
                                        'pwr': payload.power,
                                        'db': payload.snr})
                    mqtt_client.publish("py_wsjtx/{}/wspr".format(payload.id_key), mqtt_msg)

                info = "WSPR [{}]: {:10} ({:6}) db:{:4}, Freq:{:>10,}Hz, pwr:{:4}, Dist:{:>5.0f}km, Az: {:>3.0f}".format(
                            payload.now_time,
                            payload.callsign,
                            payload.grid,
                            payload.snr,
                            payload.delta_freq,
                            payload.power,
                            payload.dist,
                            payload.bearing)

                if config.log_decodes:
                    out_log.write("{}\n".format(info))

                if config.use_curses:
                    jt_curses.add_main_window(info)
                else:
                    payload.do_print()

            else:
                if config.use_curses:
                    jt_curses.add_main_window("[*] Packet type: {}".format(packet_type))
                else:
                    print("[*] Packet type: {}".format(packet_type))

    except KeyboardInterrupt:
        if config.use_curses:
            jt_curses.exit_now()
        if config.log_decodes:
            out_log.write("Closed Log at {}\n".format(datetime.datetime.now()))
            out_log.close()
        print("ctrl-c caught, exiting")
        if config.notify_alert:
            Notify.uninit()
Esempio n. 9
0
configdir = os.path.expanduser('~/.config/ham-tools')

with open(configdir + '/config.yaml') as f:
    cfg = yaml.load(f, Loader=yaml.FullLoader)

address = ' '.join(sys.argv[1:])
geolocator = Nominatim(user_agent="ON3URE_hamtools")
try:
    location = geolocator.geocode(address)

    locator1 = latlong_to_locator(cfg['qth']['latitude'],
                                  cfg['qth']['longitude'])
    locator2 = latlong_to_locator(location.latitude, location.longitude)

    heading = calculate_heading(locator1, locator2)
    longpath = calculate_heading_longpath(locator1, locator2)
    maidenhead = mh.to_maiden(location.latitude, location.longitude)

    print(
        fg('blue') + '-=' + fg('turquoise_4') + attr('bold') +
        "QTE: Bearing lookup" + attr('reset') + fg('blue') + '=-' +
        attr('reset'))
    print(fg('#884444') + attr('bold') + 'Address: ', end="")
    print(fg('dark_sea_green_3b') + location.address)
    print(fg('#884444') + attr('bold') + 'Latitude: ', end="")
    print(fg('dark_sea_green_3b') + "%.1f°" % location.latitude, end="")
    print(fg('#884444') + attr('bold') + ' Longitude: ', end="")
    print(fg('dark_sea_green_3b') + "%.1f°" % location.longitude, end="")
    print(fg('#884444') + attr('bold') + ' Grid square: ', end="")
    print(fg('dark_sea_green_3b') + maidenhead)