Building a Linux App with Python – Part 6, connecting to the repeater listing!

It’s easy to start a Python project in one file, and then add class after class and function after function in the same file – as i have in the repeater-start project. This can get unwieldy after awhile. As I am adding a type for the open-source Hearham Live Repeater Listing, I will make a new node creator that will get the repeaters out of the api. So from what I had before, just one repeater code:

class IRLPNode:
    def __init__(self, line):
        """ Unpack the line to the properties of this class: """
        [self.node, self.callsign, self.city, self.state, self.country, self.status, self.record, self.install, self.lat, self.lon, self.lastupdate, self.freq, self.offset, self.pl, self.owner, self.url, self.lastchange, self.avrsstatus] = line.split('\t')
        self.lat = float(self.lat)
        self.lon = float(self.lon)
    
    def distance(self, lat,lon):
        """ Distance in km """
        earthR = 6373
        dlat = radians(lat-self.lat)
        dlon = radians(lon-self.lon)
        a = sin(dlat/2)**2 + cos(radians(self.lat)) * cos(radians(lat)) * sin(dlon/2)**2
        c = 2*atan2(sqrt(a), sqrt(1-a))
        return earthR*c

I’ll consider this a subclass of Repeater – a class that can give distance to a certain lat/lon point, and one that can be added to the repeater listing array internally. The first thing to consider when naming this file is the import, you should not make an “os.py” or a “threading.py”, as that conflicts with “import os” for example. I built the following classes:

#!/usr/bin/python3
from math import pi, sin, cos, sqrt, atan2, radians

class Repeater:
    def distance(self, lat,lon):
        """ Distance in km """
        earthR = 6373
        dlat = radians(lat-self.lat)
        dlon = radians(lon-self.lon)
        a = sin(dlat/2)**2 + cos(radians(self.lat)) * cos(radians(lat)) * sin(dlon/2)**2
        c = 2*atan2(sqrt(a), sqrt(1-a))
        return earthR*c




#!/usr/bin/python3
from Repeater import Repeater

class IRLPNode(Repeater):
    def __init__(self, line):
        """ Unpack the line to the properties of this class: """
        [self.node, self.callsign, self.city, self.state, self.country, self.status, self.record, self.install, self.lat, self.lon, self.lastupdate, self.freq, self.offset, self.pl, self.owner, self.url, self.lastchange, self.avrsstatus] = line.split('\t')
        self.lat = float(self.lat)
        self.lon = float(self.lon)
        if float(self.freq) == 0:
            self.description = "Owned by %s" % (self.owner,)
        else:
            self.description = "Owned by %s in %s" % (self.owner, self.city)
    


#!/usr/bin/python3
from Repeater import Repeater

class HearHamRepeater(Repeater):
    def __init__(self, jsonObject):
        """ Unpack the line to the properties of this class: """
        self.callsign = jsonObject['callsign']
        self.description = jsonObject['description']
        self.owner = jsonObject['callsign']
        self.status = jsonObject['operational']
        self.url = 'https://hearham.com/repeaters/'+str(jsonObject['id'])
        self.node = jsonObject['internet_node']
        self.lat = float(jsonObject['latitude'])
        self.lon = float(jsonObject['longitude'])
        self.city = jsonObject['city']
        self.pl = jsonObject['encode']
        self.freq = jsonObject['frequency']/1000000
        self.offset = jsonObject['offset']/1000000

The above code is in Repeater.py, IRLPNode.py, HearHamRepeater.py, respectively. Now in the main file I can import the two types of repeaters that I’ll be pulling from in files.

from IRLPNode import IRLPNode
from HearHamRepeater import HearHamRepeater

Note that only the files using the libraries need the import statements. Also note that I construct the new HearHamRepeater with object as I have that from the json pull from my Hearham.com JSON api, I can read from the downloaded file like an array/dict, for example:

>>> import json
>>> val = json.load(open('repeaters.json','r'))
>>> val[0]
{'power': 'unknown', 'callsign': 'VE7RHS', 'group': 'IRLP', 'operational': 1, 'offset': -600000, 'longitude': -123.24992, 'frequency': 145270000, 'city': 'Vancouver, BC Canada', 'latitude': 49.26973, 'id': 1, 'mode': 'FM', 'description': 'Internet-connected IRLP node owned by VE7LTD.\nhttp://www.ars.ams.ubc.CA\nSee http://www.irlp.net/status/index.php?nodeid=1000', 'internet_node': '1000', 'restriction': '', 'encode': '100.0', 'decode': '100.0'}
>>> val[0]['frequency']
145270000

Now with some adjustments to bring in the Hearham repeater listing, I made this display the IRLP repeaters AND the ones that have been added to Hearham.com/repeaters, for example all the Peak Radio Association repeaters. Unfortunately now it lists some duplicates because IRLPs are repeaters:

Since the raw IRLP pull has all the info on the latest repeaters, their status, I’ll use that datasource when it is not a IRLP.

    def displayNodes(self):
        self.osm.image_remove_all()
        with open('nohtmlstatus.txt') as repfile:
            self.allrepeaters = []
            for line in repfile:
                try:
                    self.addRepeaterIcon(IRLPNode(line))
                except ValueError:
                    pass
        for repeater in json.load(open('repeaters.json')):
            #IRLP has been done in direct pull above.
            if repeater['group'] != 'IRLP':
                self.addRepeaterIcon(HearHamRepeater(repeater))
    
    def addRepeaterIcon(self, repeater):
        pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale('signaltower.svg',width=20,height=20,preserve_aspect_ratio=True)
        self.osm.image_add(repeater.lat, repeater.lon, pixbuf)
        self.allrepeaters.append(repeater)

Check out the code on github and run it… and display all the repeaters nearby!

In the next post, I show how to make an easily installable file from the Python code.

Leave a Reply

Your email address will not be published. Required fields are marked *

two + 2 =