Converters for Baofeng 1801 programming software
#!python | |
""" | |
Converts BrandMeister's CSV contact export to what Baofeng 1801 | |
programming software expects. | |
Also does some filtration to get the number of contacts under 1024. | |
Baofeng seems not to handle more than that. | |
Contact list can be downloaded from: https://brandmeister.network/?page=contactsexport | |
""" | |
import csv | |
PRIVATE_CALL="Private Call" | |
GROUP_ALL="Group All" | |
hardcoded = [ | |
[0,"Local","9", GROUP_ALL, "On", "None"], | |
[0,"TG Poland","260",GROUP_ALL,"On","None"], | |
[0,"SP Echo","260097",PRIVATE_CALL,"On","None"], | |
[0,"TG SP6","2606",GROUP_ALL,"On","None"], | |
[0,"TG DASR","26061",GROUP_ALL,"On","None"], | |
[0,"TG WiresX","260080",GROUP_ALL,"On","None"], | |
[0,"TG FusionPL","260042",GROUP_ALL,"On","None"], | |
[0,"TG SP Test","260019",GROUP_ALL,"On","None"], | |
[0,"TG Worldwide","91",GROUP_ALL,"On","None"], | |
[0,"TG Europe","92",GROUP_ALL,"On","None"], | |
[0,"TG EuroEng","923",GROUP_ALL,"On","None"], | |
[0,"TG Reddit","98003",GROUP_ALL,"On","None"], | |
[0, "Ref Check", "5000", PRIVATE_CALL, "On", "None"], | |
[0, "Ref Unlink", "4000", PRIVATE_CALL, "On", "None"] | |
] | |
with open('bm_ce.csv', 'r') as inputfile, open('output.csv', 'w') as outputfile: | |
reader = csv.reader(inputfile, delimiter=',', quotechar='"') | |
writer = csv.writer(outputfile, delimiter=',') | |
first = False | |
counter = 0 | |
writer.writerow(["Number", "Name", "Call ID", "Type", "Ring Style", "Call Receive Tone"]) | |
for row in hardcoded: | |
row[0] = counter | |
writer.writerow(row) | |
counter += 1 | |
for row in reader: | |
if row[0].startswith("260") and int(row[4]) > 20: | |
writer.writerow([counter, row[1], row[0], PRIVATE_CALL, "On", "None"]) | |
counter += 1 |
#!python3 | |
""" | |
Fetches the repeater list from przemienniki.net and converts it | |
into the channel list in CSV for Baofeng 1801. | |
Adjust COUNTRY to get repeaters from your country. | |
Thanks to SQ5IRS for fixes! | |
""" | |
from xml.dom.minidom import parseString | |
import requests | |
import csv | |
COUNTRY = 'pl' | |
DMR_NAME = 'MOTOTRBO' # przemienniki.net treats MOTOTRBO as DMR | |
MODE = '{},FM'.format(DMR_NAME) | |
OUTFILE = 'channels.csv' | |
DIGITAL_MODE = 'Digital' | |
ANALOG_MODE = 'Analog' | |
OUTPUT_CSV_HEADER = ["Number", "Name", "Rx Freq", "Tx Freq", "Ch Mode", "Power", "Rx Tone", "Tx Tone", "Color Code", | |
"Rx Group List", "Contact", "Repeater Slot", "Bandwidth", "Squelch Level"] | |
HARDCODED = [ | |
["0", "DMR 2m", "144.55000", "144.55000", "Digital", "High", "None", "None", "1", "0", "2", "2", "12.5", "0"], | |
["0", "DMR 70cm", "433.55000", "433.55000", "Digital", "High", "None", "None", "1", "0", "2", "2", "12.5", "0"], | |
] | |
channel_counter = 0 | |
def getType(repeater): | |
for element in repeater.getElementsByTagName("mode"): | |
if element.firstChild.nodeValue == DMR_NAME: | |
return DIGITAL_MODE | |
return ANALOG_MODE # there may be multiple modes. Select digital if DMR is one of them, else default to analog | |
def getValueGetter(repeater): | |
def getValue(paramName, attr=None): | |
for element in repeater.getElementsByTagName(paramName): | |
if attr is None: | |
return element.firstChild.nodeValue | |
if element.attributes[attr[0]].value == attr[1]: | |
return element.firstChild.nodeValue | |
return "" | |
return getValue | |
def getRepeaterEntry(repeater, timeSlot='1', namePostfix=""): | |
global channel_counter | |
getValue = getValueGetter(repeater) | |
retval = [ | |
channel_counter, | |
getValue('qra') + namePostfix, | |
getValue('qrg', ("type", "tx")), | |
getValue('qrg', ("type", "rx")), | |
getType(repeater), | |
'High', | |
getValue('ctcss', ("type", "tx")), | |
getValue('ctcss', ("type", "rx")), | |
'1', # Color Code isn't unfortunately included in przemienniki.net database | |
'1', # Rx Group List is radio specific | |
'1', # Contact is radio specific | |
timeSlot, | |
'12.5', | |
'0' | |
] | |
channel_counter += 1 | |
return retval | |
def getRepeaterEntries(repeater): | |
if getType(repeater) == DIGITAL_MODE: | |
return [ | |
getRepeaterEntry(repeater, '1', " TS1"), | |
getRepeaterEntry(repeater, '2', " TS2") | |
] | |
else: | |
return [getRepeaterEntry(repeater, '1')] | |
def main(): | |
url = 'https://przemienniki.net/export/rxf.xml?country={}&onlyworking&mode={}'.format(COUNTRY, MODE) | |
r = requests.get(url) | |
response = r.text | |
indata = parseString(response.encode("ASCII", 'ignore')) | |
with open(OUTFILE, 'w') as outputfile: | |
writer = csv.writer(outputfile, delimiter=',') | |
writer.writerow(OUTPUT_CSV_HEADER) | |
for item in HARDCODED: | |
global channel_counter | |
item[0] = channel_counter | |
writer.writerow(item) | |
channel_counter += 1 | |
repeaters = indata.getElementsByTagName('repeater') | |
for repeater in repeaters: | |
writer.writerows(getRepeaterEntries(repeater)) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment