Compare commits

..

No commits in common. "c5c0081976157651b799efc793c576331e36b497" and "b551a09b7e1b4124084176f896e239ae2f21c11a" have entirely different histories.

5 changed files with 45 additions and 6343 deletions

2
.gitignore vendored
View file

@ -1,2 +0,0 @@
# ignore our binary Excel file
*.xlsx

View file

@ -22,7 +22,7 @@ pd.set_option("display.max_rows", 150)
# point to our various input files - adjust this to your environment # point to our various input files - adjust this to your environment
data_dir = '/home/syncthing/ham-radio/ARES-RACES/Nets--PNW_ARES_DMR_Weekly_Net' data_dir = '/home/ed/syncthing/ham-radio/ARES-RACES/Nets--PNW_ARES_DMR_Weekly_Net'
filename = 'Check_In_Data.xlsx' filename = 'Check_In_Data.xlsx'
data_file = os.path.join(data_dir, filename) data_file = os.path.join(data_dir, filename)
output_file = os.path.join(data_dir, "PNW_Digital_ARES_EMCOMM_Weekly_Net_Check_In_Form.txt") output_file = os.path.join(data_dir, "PNW_Digital_ARES_EMCOMM_Weekly_Net_Check_In_Form.txt")
@ -88,18 +88,18 @@ checkins_df["Date"] = pd.to_datetime(checkins_df["Date"]).dt.strftime('%Y-%m-%d'
callinfo_df = pd.read_excel(xls, "Call_Data", dtype=str) callinfo_df = pd.read_excel(xls, "Call_Data", dtype=str)
#print("callinfo_df:") #print("callinfo_df:")
#print(callinfo_df) #print(callinfo_df)
hoip_dir_df = pd.read_excel(xls, "hoip_subscribers", dtype=str) hh_dir_df = pd.read_excel(xls, "Hamshack_Hotline", dtype=str)
#print("hoip_dir_df:") #print("hh_dir_df:")
#print(hoip_dir_df) #print(hh_dir_df)
# build dictionary of HH phone numbers # build dictionary of HH phone numbers
hoip_phone_dict = {"Callsign" : "HH Number"} hh_phone_dict = {"Callsign" : "HH Number"}
for i,row in hoip_dir_df.iterrows(): for i,row in hh_dir_df.iterrows():
callsign = row.iloc[1] callsign = row.iloc[1]
hoip_num = row.iloc[0] hh_num = row.iloc[7]
# we only add the hoip number first seen for a unique callsign # we only add the hh number first seen for a unique callsign
if callsign not in hoip_phone_dict.keys(): if callsign not in hh_phone_dict.keys():
hoip_phone_dict.update({callsign : hoip_num}) hh_phone_dict.update({callsign : hh_num})
# fill in any missing data (NAN's) with default text # fill in any missing data (NAN's) with default text
callinfo_df.fillna({'Name' : ''}, inplace=True) callinfo_df.fillna({'Name' : ''}, inplace=True)
@ -127,27 +127,27 @@ for i,row in checkins_df.iterrows():
# build dictionary of call info indexed by callsign # build dictionary of call info indexed by callsign
call_data_dict = {} call_data_dict = {}
for i,row in callinfo_df.iterrows(): for i,row in callinfo_df.iterrows():
# row of data is call, name, state, district, county, affiliation, hoip_num # row of data is call, name, state, district, county, affiliation, hh_num
# dictionary becomes: { call: [name[0], state[1], district[2], county[3], affiliation[4]], hoip_num[5]} # dictionary becomes: { call: [name[0], state[1], district[2], county[3], affiliation[4]], hh_num[5]}
callsign = row.iloc[0] callsign = row.iloc[0]
if callsign in hoip_phone_dict.keys(): if callsign in hh_phone_dict.keys():
hoip_num = hoip_phone_dict[callsign] hh_num = hh_phone_dict[callsign]
else: else:
hoip_num = "" hh_num = ""
call_data_dict.update({callsign:[row.iloc[1],row.iloc[2],row.iloc[3],row.iloc[4],row.iloc[5],hoip_num]}) call_data_dict.update({callsign:[row.iloc[1],row.iloc[2],row.iloc[3],row.iloc[4],row.iloc[5],hh_num]})
# build checkin_form_dict dictionary # build checkin_form_dict dictionary
checkin_form_dict = blank_checkin_form_dict checkin_form_dict = blank_checkin_form_dict
for call in call_data_dict.keys(): for call in call_data_dict.keys():
#print("Looking at:", call) #print("Looking at:", call)
#if call in hoip_phone_dict.keys(): #if call in hh_phone_dict.keys():
#print("Call "+call+" has HOIP #"+hoip_phone_dict[call]) #print("Call "+call+" has HH VOIP #"+hh_phone_dict[call])
call_state = call_data_dict[call][1] call_state = call_data_dict[call][1]
call_dist = call_data_dict[call][2] call_dist = call_data_dict[call][2]
call_county = call_data_dict[call][3] call_county = call_data_dict[call][3]
call_affil = call_data_dict[call][4] call_affil = call_data_dict[call][4]
call_hoip_num = call_data_dict[call][5] call_hh_num = call_data_dict[call][5]
#print("State, Dist, Cnty, Affil, HH Num: ", call_state, call_dist, call_county, call_affil, call_hoip_num) #print("State, Dist, Cnty, Affil, HH Num: ", call_state, call_dist, call_county, call_affil, call_hh_num)
# sanity check the data - error if not found in dictionary keys... # sanity check the data - error if not found in dictionary keys...
# print("Verifying at: ", call, call_state, call_dist, call_county) # print("Verifying at: ", call, call_state, call_dist, call_county)
@ -218,8 +218,8 @@ with open(output_file,"w") as outfile:
checkin_str = "" checkin_str = ""
if checkin_count > 0: if checkin_count > 0:
outfile.write(" "+call+", "+call_name+checkin_str) outfile.write(" "+call+", "+call_name+checkin_str)
if call in hoip_phone_dict.keys(): if call in hh_phone_dict.keys():
outfile.write(", HOIP #"+hoip_phone_dict[call]) outfile.write(", HH VOIP #"+hh_phone_dict[call])
if call_affil != "": if call_affil != "":
outfile.write(", "+call_affil+"\n") outfile.write(", "+call_affil+"\n")
else: else:
@ -237,8 +237,8 @@ with open(output_file,"w") as outfile:
checkin_str = "" checkin_str = ""
if checkin_count > 0: if checkin_count > 0:
outfile.write(" "+call+", "+call_data_dict[call][0]+checkin_str) outfile.write(" "+call+", "+call_data_dict[call][0]+checkin_str)
if call in hoip_phone_dict.keys(): if call in hh_phone_dict.keys():
outfile.write(", HOIP #"+hoip_phone_dict[call]) outfile.write(", HH VOIP #"+hh_phone_dict[call])
affil = call_data_dict[call][4] affil = call_data_dict[call][4]
if affil != '': if affil != '':
outfile.write(", "+affil+"\n") outfile.write(", "+affil+"\n")
@ -263,8 +263,8 @@ with open(output_file,"w") as outfile:
checkin_count = 0 checkin_count = 0
checkin_str = "" checkin_str = ""
outfile.write(" "+call+", "+call_data_dict[call][0]+checkin_str) outfile.write(" "+call+", "+call_data_dict[call][0]+checkin_str)
if call in hoip_phone_dict.keys(): if call in hh_phone_dict.keys():
outfile.write(", HOIP #"+hoip_phone_dict[call]) outfile.write(", HH VOIP #"+hh_phone_dict[call])
affil = call_data_dict[call][4] affil = call_data_dict[call][4]
if affil != '': if affil != '':
outfile.write(", "+affil+"\n") outfile.write(", "+affil+"\n")
@ -337,21 +337,14 @@ for net_day in net_day_list:
with open(output_file,"w") as outfile: with open(output_file,"w") as outfile:
# Opening text # Opening text
headertext = '\n'.join([ outfile.write("\n ")
'PNW Digital ARES & EmComm Check-In Net - '+str(num_checkins)+ outfile.write("PNW Digital ARES & EMCOMM Check-In Net - "+str(num_checkins)+" check-ins on "+net_day+"\n")
' check-ins on '+net_day+'\n', outfile.write("\n")
'There were '+str(num_checkins)+' check-ins on '+net_day+' to the Pacific', outfile.write("We had a total of "+str(num_checkins)+" check-ins on "+net_day+" to the Pacific Northwest (PNW)\n")
'Northwest (PNW) Digital ARES & EmComm Check-In Net.', outfile.write("Digital ARES & EMCOMM Check-In Net. Below is the detailed check-in list grouped\n")
' ', outfile.write("by ARRL ARES districts. If any of the info (i.e. name or agency affiliation) below is\n")
'The following is the detailed check-in list grouped', outfile.write("incomplete or incorrect, please IM me on Jabber/XMPP (ed@n7ekb.net), or\n")
'by our region\'s ARRL ARES districts. If any of the', outfile.write("e-mail \"ed@n7ekb.net\" with the correction(s).\n\n\n")
'info (i.e. name or agency affiliation) below is',
'incomplete or incorrect, please IM me on Jabber/',
'XMPP at n7ekb@n7ekb.net, e-mail me at ed@n7ekb.net, or',
'call me on HOIP extension 103675 with your updates.',
'\n\n'
])
outfile.write(headertext)
# Check-in details # Check-in details
for state in sorted(report_dict): for state in sorted(report_dict):
@ -367,10 +360,8 @@ for net_day in net_day_list:
cur_call_list.sort() cur_call_list.sort()
for call in cur_call_list: for call in cur_call_list:
affil = call_data_dict[call][4] affil = call_data_dict[call][4]
hoip_num = call_data_dict[call][5] hh_num = call_data_dict[call][5]
outfile.write(" "+call+", "+call_data_dict[call][0]) outfile.write(" "+call+", "+call_data_dict[call][0])
if hoip_num != '':
outfile.write(", HOIP #"+hoip_num)
if affil != '': if affil != '':
outfile.write(", "+affil+"\n") outfile.write(", "+affil+"\n")
else: else:
@ -382,10 +373,8 @@ for net_day in net_day_list:
cur_call_list.sort() cur_call_list.sort()
for call in cur_call_list: for call in cur_call_list:
affil = call_data_dict[call][4] affil = call_data_dict[call][4]
hoip_num = call_data_dict[call][5] hh_num = call_data_dict[call][5]
outfile.write(" "+call+", "+call_data_dict[call][0]) outfile.write(" "+call+", "+call_data_dict[call][0])
if hoip_num != '':
outfile.write(", HOIP #"+hoip_num)
if affil != '': if affil != '':
outfile.write(", "+affil+"\n") outfile.write(", "+affil+"\n")
else: else:
@ -401,10 +390,8 @@ for net_day in net_day_list:
cur_call_list.sort() cur_call_list.sort()
for call in cur_call_list: for call in cur_call_list:
affil = call_data_dict[call][4] affil = call_data_dict[call][4]
hoip_num = call_data_dict[call][5] hh_num = call_data_dict[call][5]
outfile.write(" "+call+", "+call_data_dict[call][0]) outfile.write(" "+call+", "+call_data_dict[call][0])
if hoip_num != '':
outfile.write(", HOIP #"+hoip_num)
if affil != '': if affil != '':
outfile.write(", "+affil+"\n") outfile.write(", "+affil+"\n")
else: else:
@ -413,24 +400,14 @@ for net_day in net_day_list:
outfile.write("\n") outfile.write("\n")
# output the footer text... # output the footer text...
footer = '\n'.join([ outfile.write("\nAbout the net:\n\n")
'About the net:\n', outfile.write("The PNW Digital ARES & EMCOMM Check-In Net is held every Sunday evening at 7:30 PM local\n")
'The PNW Digital ARES & EMCOMM Check-In Net is held', outfile.write("time on PNW Regional, DMR talk group 31771 (available on both the PNW Digital http://pnwdigital.net\n")
'every Sunday evening at 7:30 PM local time on PNW', outfile.write("and Brandmeister DMR networks). Anyone interested in Amateur Radio Emergency Communications is\n")
'Regional, DMR talkgroup 31771. DMR Talk Group 31771 is', outfile.write("welcome to check-in. The net is an opportunity for DMR-capable ARES and EMCOMM hams to exercise\n")
'available on both the PNW Digital and the Brandmeister', outfile.write("their DMR equipment in a regional directed net. The net demonstrates the wide coverage area and\n")
'DMR networks. Anyone interested in Amateur Radio and', outfile.write("capability of DMR repeaters and hot spots in our Pacific Northwest region. It also highlights the\n")
'Emergency Communications is welcome to check-in. The', outfile.write("wide range of EMCOMM-related organizations who have members with DMR capability.\n\n")
'net is an opportunity for DMR-capable ARES and EmComm',
'hams to exercise their DMR equipment in a regional,',
'directed net. The net demonstrates the wide coverage',
'area and capability of DMR repeaters and hot spots in',
'our Pacific Northwest region. It also highlights the',
'wide range of EmComm-related organizations who have',
'members with DMR capability.\n\n',
'#net-reports #hamradio #EmComm #ARES #DMR #HOIP #PNWDigital\n'
])
outfile.write(footer)
# close this week's report file # close this week's report file
outfile.close() outfile.close()

File diff suppressed because it is too large Load diff

View file

@ -1,56 +0,0 @@
from ldap3 import Server, Connection, ALL, SUBTREE
import pandas as pd
# LDAP connection details from the wiki
server_url = 'ldap://207.246.98.219:389' # Server and port (no TLS, as per "TLS Mode: LDAP or No" use 'ldaps://' if TLS needed)
search_base = 'ou=people,dc=hamsoverip,dc=com'
search_filter = '(telephoneNumber=*)' # Fetch all entries with an extension; adjust if needed, e.g., '(objectClass=person)'
attributes = ['cn', 'sn', 'telephoneNumber'] # Key attributes; add more if you discover others like 'callsign'
# Connect anonymously (no auth)
server = Server(server_url, get_info=ALL)
conn = Connection(server, auto_bind=True) # No user/password
# Perform the search
conn.search(
search_base=search_base,
search_filter=search_filter,
search_scope=SUBTREE,
attributes=attributes
)
# Extract data
data = []
for entry in conn.entries:
extension = entry.telephoneNumber.value if 'telephoneNumber' in entry else ''
cn_value = entry.cn.value if 'cn' in entry else ''
sn_value = entry.sn.value if 'sn' in entry else ''
# clean up data
hoipnumber = extension.partition(' ')[0]
callsign = cn_value.partition(' ')[0]
hamname = sn_value.partition(' ')[0]
if hoipnumber: # Only include entries with extensions
data.append({
'HOIP Extension': hoipnumber,
'Call': callsign,
'Name': hamname # Include raw for reference
})
# Save to CSV
if data:
df = pd.DataFrame(data)
# CSV output for debugging...
df.to_csv('hoip_subscribers.csv', index=False)
print(f'Saved {len(data)} entries to hoip_subscribers.csv')
# Excel output for production...
df.to_excel('hoip_subscribers.xlsx', index=False)
print(f'Saved {len(data)} entries to hoip_subscribers.xlsx')
else:
print('No entries found check filter or connection.')
# Unbind
conn.unbind()

View file

@ -1,14 +0,0 @@
# shell.nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [
(pkgs.python3.withPackages (ps: with ps; [
numpy
openpyxl
pandas
python-dateutil
]))
];
}