[chirp_devel] [PATCH] Add import from RadioReference.com. Feature #114
Tom Hayward
Tue Apr 10 20:43:37 PDT 2012
# HG changeset patch
# User Tom Hayward <tom at tomh.us>
# Date 1334115754 21600
# Node ID 7f61e3dfb31f2be17279e79e01e85f05d98bef13
# Parent 806b80ebe58e7d62f62ee9d6e9ab0fc929236e49
Add import from RadioReference.com. Feature #114
diff -r 806b80ebe58e -r 7f61e3dfb31f chirp/chirp_common.py
--- a/chirp/chirp_common.py Tue Apr 10 10:00:18 2012 -0600
+++ b/chirp/chirp_common.py Tue Apr 10 21:42:34 2012 -0600
@@ -60,7 +60,7 @@
"->DTCS",
]
-MODES = ["WFM", "FM", "NFM", "AM", "NAM", "DV", "USB", "LSB", "CW", "RTTY", "DIG", "PKT", "NCW", "NCWR", "CWR"]
+MODES = ["WFM", "FM", "NFM", "AM", "NAM", "DV", "USB", "LSB", "CW", "RTTY", "DIG", "PKT", "NCW", "NCWR", "CWR", "P25"]
STD_6M_OFFSETS = [
(51620000, 51980000, -500000),
diff -r 806b80ebe58e -r 7f61e3dfb31f chirp/directory.py
--- a/chirp/directory.py Tue Apr 10 10:00:18 2012 -0600
+++ b/chirp/directory.py Tue Apr 10 21:42:34 2012 -0600
@@ -1,4 +1,5 @@
# Copyright 2010 Dan Smith <dsmith at danplanet.com>
+# Copyright 2012 Tom Hayward <tom at tomh.us>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -17,7 +18,7 @@
import tempfile
from chirp import icf
-from chirp import chirp_common, util, rfinder, errors
+from chirp import chirp_common, util, rfinder, radioreference, errors
def radio_class_id(cls):
ident = "%s_%s" % (cls.VENDOR, cls.MODEL)
@@ -79,6 +80,12 @@
raise Exception("Unsupported model")
def get_radio_by_image(image_file):
+ if image_file.startswith("radioreference://"):
+ method, _, zipcode, username, password = image_file.split("/", 4)
+ rr = radioreference.RadioReferenceRadio(None)
+ rr.set_params(zipcode, username, password)
+ return rr
+
if image_file.startswith("rfinder://"):
method, _, email, passwd, lat, lon = image_file.split("/")
rf = rfinder.RFinderRadio(None)
diff -r 806b80ebe58e -r 7f61e3dfb31f chirp/radioreference.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chirp/radioreference.py Tue Apr 10 21:42:34 2012 -0600
@@ -0,0 +1,156 @@
+# Copyright 2012 Tom Hayward <tom at tomh.us>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from chirp import chirp_common, CHIRP_VERSION, errors
+try:
+ from suds.client import Client
+ HAVE_SUDS = True
+except ImportError:
+ HAVE_SUDS = False
+
+MODES = {
+ "FM" : "FM",
+ "AM" : "AM",
+ "FMN" : "NFM",
+ "D-STAR": "DV",
+ "USB" : "USB",
+ "LSB" : "LSB",
+ "P25" : "P25",
+}
+
+class RadioReferenceRadio(chirp_common.Radio):
+ VENDOR = "Radio Reference LLC"
+ MODEL = "RadioReference.com"
+
+ URL = "http://api.radioreference.com/soap2/?wsdl"
+ APPKEY = "46785108"
+
+ def __init__(self, *args, **kwargs):
+ chirp_common.Radio.__init__(self, *args, **kwargs)
+
+ if not HAVE_SUDS:
+ raise errors.RadioError(
+ "Suds library required for RadioReference.com import.\n" + \
+ "Try installing your distribution's python-suds package.")
+
+ self._auth = {"appKey": self.APPKEY, "username": "", "password": ""}
+ self._client = Client(self.URL)
+ self._freqs = None
+ self._modes = None
+
+ def set_params(self, zip, username, password):
+ self._zip = zip
+ self._auth["username"] = username
+ self._auth["password"] = password
+
+ def do_fetch(self):
+ """Fetches frequencies for all subcategories in a county."""
+ self._freqs = []
+
+ zipcode = self._client.service.getZipcodeInfo(self._zip, self._auth)
+ county = self._client.service.getCountyInfo(zipcode.ctid, self._auth)
+ for cat in county.cats:
+ print "Fetching category:", cat.cName
+ for subcat in cat.subcats:
+ print "\t", subcat.scName
+ result = self._client.service.getSubcatFreqs(subcat.scid, self._auth)
+ self._freqs += result
+ for agency in county.agencyList:
+ agency = self._client.service.getAgencyInfo(agency.aid, self._auth)
+ for cat in agency.cats:
+ print "Fetching category:", cat.cName
+ for subcat in cat.subcats:
+ print "\t", subcat.scName
+ result = self._client.service.getSubcatFreqs(subcat.scid, self._auth)
+ self._freqs += result
+
+ def get_features(self):
+ if not self._freqs:
+ self.do_fetch()
+
+ rf = chirp_common.RadioFeatures()
+ rf.memory_bounds = (0, len(self._freqs)-1)
+ return rf
+
+ def get_raw_memory(self, number):
+ return repr(self._freqs[number])
+
+ def get_memory(self, number):
+ if not self._freqs:
+ self.do_fetch()
+
+ freq = self._freqs[number]
+
+ mem = chirp_common.Memory()
+ mem.number = number
+
+ mem.name = freq.alpha or freq.descr or ""
+ mem.freq = chirp_common.parse_freq(str(freq.out))
+ if freq["in"] == 0.0:
+ mem.duplex = ""
+ else:
+ mem.duplex = "split"
+ mem.offset = chirp_common.parse_freq(str(freq["in"]))
+ if freq.tone is not None:
+ if str(freq.tone) == "CSQ": # Carrier Squelch
+ mem.tmode = ""
+ else:
+ try:
+ tone, tmode = freq.tone.split(" ")
+ except:
+ tone, tmode = None, None
+ if tmode == "PL":
+ mem.tmode = "TSQL"
+ mem.rtone = mem.ctone = float(tone)
+ elif tmode == "DPL":
+ mem.tmode = "DTCS"
+ mem.dtcs = int(tone)
+ else:
+ print "Error: unsupported tone"
+ print freq
+ try:
+ mem.mode = self._get_mode(freq.mode)
+ except KeyError:
+ # skip memory if mode is unsupported
+ mem.empty = True
+ return mem
+ mem.comment = freq.descr.strip()
+
+ return mem
+
+ def _get_mode(self, modeid):
+ if not self._modes:
+ self._modes = {}
+ for mode in self._client.service.getMode("0", self._auth):
+ # sax.text.Text cannot be coerced directly to int
+ self._modes[int(str(mode.mode))] = str(mode.modeName)
+ return MODES[self._modes[int(str(modeid))]]
+
+
+def main():
+ """
+ Usage:
+ cd ~/src/chirp.hg
+ python ./chirp/radioreference.py [ZIPCODE] [USERNAME] [PASSWORD]
+ """
+ import sys
+ rrr = RadioReferenceRadio(None)
+ rrr.set_params(zip=sys.argv[1], username=sys.argv[2], password=sys.argv[3])
+ rrr.do_fetch()
+ print rrr.get_raw_memory(0)
+ print rrr.get_memory(0)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff -r 806b80ebe58e -r 7f61e3dfb31f chirpui/mainapp.py
--- a/chirpui/mainapp.py Tue Apr 10 10:00:18 2012 -0600
+++ b/chirpui/mainapp.py Tue Apr 10 21:42:34 2012 -0600
@@ -1,4 +1,5 @@
# Copyright 2008 Dan Smith <dsmith at danplanet.com>
+# Copyright 2012 Tom Hayward <tom at tomh.us>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -96,7 +97,7 @@
set_action_sensitive(i, eset is not None and not mmap_sens)
for i in ["export", "import", "close", "columns", "rbook", "rfinder",
- "stock", "move_up", "move_dn", "exchange",
+ "stock", "move_up", "move_dn", "exchange", "radioreference",
"cut", "copy", "paste", "delete", "viewdeveloper"]:
set_action_sensitive(i, eset is not None)
@@ -872,6 +873,60 @@
self.window.set_cursor(None)
+ def do_radioreference_prompt(self):
+ fields = {"1Username" : (gtk.Entry(), lambda x: x),
+ "2Password" : (gtk.Entry(), lambda x: x),
+ "3Zipcode" : (gtk.Entry(), lambda x: x),
+ }
+
+ d = inputdialog.FieldDialog(title="RadioReference.com Query", parent=self)
+ for k in sorted(fields.keys()):
+ d.add_field(k[1:], fields[k][0])
+ fields[k][0].set_text(CONF.get(k[1:], "radioreference") or "")
+ fields[k][0].set_visibility(k != "2Password")
+
+ while d.run() == gtk.RESPONSE_OK:
+ valid = True
+ for k in sorted(fields.keys()):
+ widget, validator = fields[k]
+ try:
+ if validator(widget.get_text()):
+ CONF.set(k[1:], widget.get_text(), "radioreference")
+ continue
+ except Exception:
+ pass
+ common.show_error("Invalid value for %s" % k[1:])
+ valid = False
+ break
+
+ if valid:
+ d.destroy()
+ return True
+
+ d.destroy()
+ return False
+
+ def do_radioreference(self):
+ self.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
+ if not self.do_radioreference_prompt():
+ self.window.set_cursor(None)
+ return
+
+ username = CONF.get("Username", "radioreference")
+ passwd = CONF.get("Password", "radioreference")
+ zipcode = CONF.get("Zipcode", "radioreference")
+
+ # Do this in case the import process is going to take a while
+ # to make sure we process events leading up to this
+ gtk.gdk.window_process_all_updates()
+ while gtk.events_pending():
+ gtk.main_iteration(False)
+
+ eset = self.get_current_editorset()
+ count = eset.do_import("radioreference://%s/%s/%s" % (zipcode, username, passwd))
+
+ self.window.set_cursor(None)
+
def do_export(self):
types = [(_("CSV Files") + " (*.csv)", "csv"),
(_("CHIRP Files") + " (*.chirp)", "chirp"),
@@ -1079,6 +1134,8 @@
self.do_import()
elif action == "rfinder":
self.do_rfinder()
+ elif action == "radioreference":
+ self.do_radioreference()
elif action == "export":
self.do_export()
elif action == "rbook":
@@ -1151,6 +1208,7 @@
<menu action="radio" name="radio">
<menuitem action="download"/>
<menuitem action="upload"/>
+ <menuitem action="radioreference"/>
<menuitem action="rbook"/>
<menuitem action="rfinder"/>
<menu action="stock" name="stock"/>
@@ -1197,6 +1255,7 @@
('upload', None, _("Upload To Radio"), "<Alt>u", None, self.mh),
('import', None, _("Import"), "<Alt>i", None, self.mh),
('export', None, _("Export"), "<Alt>x", None, self.mh),
+ ('radioreference', None, _("Import from RadioReference.com"), None, None, self.mh),
('rfinder', None, _("Import from RFinder"), None, None, self.mh),
('export_chirp', None, _("CHIRP Native File"), None, None, self.mh),
('export_csv', None, _("CSV File"), None, None, self.mh),
More information about the chirp_devel
mailing list