mirror of
https://github.com/loradar/loradar_tool.git
synced 2026-03-28 17:43:00 +01:00
1127 lines
40 KiB
Python
1127 lines
40 KiB
Python
### Libraries to load
|
|
import glob, matplotlib, pprint, requests, math, time, os
|
|
import pandas as pd
|
|
import numpy as np
|
|
from collections import Counter
|
|
from itertools import repeat
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
|
### Loading the data
|
|
os.chdir = ("/home/pi/lora_gateway/util_pkt_logger")
|
|
docs = glob.glob(os.chdir + "/*.csv")
|
|
|
|
if len(docs) > 1:
|
|
print("1. Reading " + str(len(docs)) + " csv files...")
|
|
all_dat = []
|
|
for doc in docs:
|
|
all_dat.append(pd.read_csv(doc, encoding = 'unicode_escape'))
|
|
|
|
every = pd.concat(all_dat)
|
|
every.reset_index(inplace=True)
|
|
every = every.dropna(subset=["UTC timestamp"])
|
|
every = every.drop("index", axis=1)
|
|
|
|
elif len(docs) == 1:
|
|
print("1. Reading one csv file...")
|
|
print(docs)
|
|
every = pd.read_csv(docs[0], encoding = 'unicode_escape')
|
|
every.reset_index(inplace=True)
|
|
every = every.dropna(subset=["UTC timestamp"])
|
|
every = every.drop("index", axis=1)
|
|
|
|
elif len(docs) == 0:
|
|
print("ERROR: No Data Files!")
|
|
exit()
|
|
|
|
|
|
### Filtering the data for ABP
|
|
print("2. Filtering the data for ABP...")
|
|
info = every.payload
|
|
info = list(map(str, info)) # Convert payload to string. This is needed as some payloads only have integers.
|
|
devs = []
|
|
fcnts = []
|
|
mhdrs = []
|
|
fctrls = []
|
|
devaddr_revl = []
|
|
fcnt_revl = []
|
|
devaddr_len = 8
|
|
|
|
for i in info:
|
|
devaddr = i[2:11].split("-")
|
|
devaddr = "".join(devaddr)
|
|
fcnt = i[13:17].split("-")
|
|
fcnt = "".join(fcnt)
|
|
fctrl = i[11:13].split("-")
|
|
fctrl = "".join(fctrl)
|
|
mhdr = i[:2].split("-")
|
|
mhdr = "".join(mhdr)
|
|
devs.append(devaddr)
|
|
fcnts.append(fcnt)
|
|
fctrls.append(fctrl)
|
|
mhdrs.append(mhdr)
|
|
|
|
# reversing the little endian form of DevAddr and Fcnt
|
|
for row in devs:
|
|
fixed = []
|
|
for j in range(int(len(row)/2)):
|
|
fixed.append(row[j*2:(j+1)*2])
|
|
fixed.reverse()
|
|
devaddr_rev = "".join(fixed)
|
|
devaddr_revl.append(devaddr_rev)
|
|
|
|
for row in fcnts:
|
|
fixed = []
|
|
for j in range(int(len(row)/2)):
|
|
fixed.append(row[j*2:(j+1)*2])
|
|
fixed.reverse()
|
|
fcnt_rev = "".join(fixed)
|
|
fcnt_revl.append(fcnt_rev)
|
|
|
|
# Remove payloads shorter than the length of DevAddr, as these will not provide sufficient information to identify ABP devices
|
|
ttn_addr = []
|
|
all_addr = []
|
|
other_addr = []
|
|
network = []
|
|
activation = []
|
|
for addr in devaddr_revl:
|
|
if len(addr) == devaddr_len:
|
|
# Network prefix assignments to the World
|
|
if addr[:2] == "26" or addr[:2] == "27":
|
|
ttn_addr.append(addr) # potential DevAddr from TTN
|
|
all_addr.append(addr)
|
|
network.append("World: The Things Network")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "04" or addr[:2] == "05":
|
|
all_addr.append(addr)
|
|
network.append("World: Actility")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "10" or addr[:2] == "11":
|
|
all_addr.append(addr)
|
|
network.append("World: Orbiwise")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "1a" or addr[:2] == "1b":
|
|
all_addr.append(addr)
|
|
network.append("World: SK Telecom")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "1c" or addr[:2] == "1d":
|
|
all_addr.append(addr)
|
|
network.append("World: SagemCom")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "24" or addr[:2] == "25":
|
|
all_addr.append(addr)
|
|
network.append("World: Kerlink")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "2a" or addr[:2] == "2b":
|
|
all_addr.append(addr)
|
|
network.append("World: Cisco Systems")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "2e" or addr[:2] == "2f":
|
|
all_addr.append(addr)
|
|
network.append("World: MultiTech Systems")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "30" or addr[:2] == "31":
|
|
all_addr.append(addr)
|
|
network.append("World: Loriot")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "32" or addr[:2] == "33":
|
|
all_addr.append(addr)
|
|
network.append("World: NNNCo")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "34" or addr[:2] == "35":
|
|
all_addr.append(addr)
|
|
network.append("World: Flashnet")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "36" or addr[:2] == "37":
|
|
all_addr.append(addr)
|
|
network.append("World: TrackNet")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "38" or addr[:2] == "39":
|
|
all_addr.append(addr)
|
|
network.append("World: Lar.Tech")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "3a" or addr[:2] == "3b":
|
|
all_addr.append(addr)
|
|
network.append("World: Swiss Led")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "42" or addr[:2] == "43":
|
|
all_addr.append(addr)
|
|
network.append("World: Patavina Technologies")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "48" or addr[:2] == "49":
|
|
all_addr.append(addr)
|
|
network.append("World: Gimasi")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "4a" or addr[:2] == "4b":
|
|
all_addr.append(addr)
|
|
network.append("World: Talkpool")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "4e" or addr[:2] == "4f":
|
|
all_addr.append(addr)
|
|
network.append("World: MCF88 SRL")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "52" or addr[:2] == "53":
|
|
all_addr.append(addr)
|
|
network.append("World: GIoT")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "54" or addr[:2] == "55":
|
|
all_addr.append(addr)
|
|
network.append("World: M2B Communications")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "5a" or addr[:2] == "5b":
|
|
all_addr.append(addr)
|
|
network.append("World: Rai Way")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "5c" or addr[:2] == "5d":
|
|
all_addr.append(addr)
|
|
network.append("World: Levikom")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "60" or addr[:2] == "61":
|
|
all_addr.append(addr)
|
|
network.append("World: SoftBank")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "62" or addr[:2] == "63":
|
|
all_addr.append(addr)
|
|
network.append("World: Inmarsat")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e006" or addr[:4] == "e007":
|
|
all_addr.append(addr)
|
|
network.append("World: IOTCAN")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e00a" or addr[:4] == "e00b":
|
|
all_addr.append(addr)
|
|
network.append("World: IoT Network AS")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e00e" or addr[:4] == "e00f":
|
|
all_addr.append(addr)
|
|
network.append("World: EDF")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e018" or addr[:4] == "e019":
|
|
all_addr.append(addr)
|
|
network.append("World: SenSys")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e01c" or addr[:4] == "e01d":
|
|
all_addr.append(addr)
|
|
network.append("World: Spark")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e020" or addr[:4] == "e021":
|
|
all_addr.append(addr)
|
|
network.append("World: Senet")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e026" or addr[:4] == "e027":
|
|
all_addr.append(addr)
|
|
network.append("World: Actility")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e02a" or addr[:4] == "e02b":
|
|
all_addr.append(addr)
|
|
network.append("World: Kerlink")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e02c" or addr[:4] == "e02d":
|
|
all_addr.append(addr)
|
|
network.append("World: Cisco")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e02e" or addr[:4] == "e02f":
|
|
all_addr.append(addr)
|
|
network.append("World: Schneider Electric")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e030" or addr[:4] == "e031":
|
|
all_addr.append(addr)
|
|
network.append("World: ZENNER")
|
|
activation.append("ABP")
|
|
elif addr[:4] == "e038" or addr[:4] == "e039":
|
|
all_addr.append(addr)
|
|
network.append("World: MachineQ/Comcast")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc0004" or addr[:6] == "fc0005" or addr[:6] == "fc0006" or addr[:6] == "fc0007":
|
|
all_addr.append(addr)
|
|
network.append("World: Nordic Automation Systems")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc0008" or addr[:6] == "fc0009" or addr[:6] == "fc000a" or addr[:6] == "fc000b":
|
|
all_addr.append(addr)
|
|
network.append("World: ResIOT")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc000c" or addr[:6] == "fc000d" or addr[:6] == "fc000e" or addr[:6] == "fc000f":
|
|
all_addr.append(addr)
|
|
network.append("World: SYSDEV")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc0020" or addr[:6] == "fc0021" or addr[:6] == "fc0022" or addr[:6] == "fc0023":
|
|
all_addr.append(addr)
|
|
network.append("World: Definium Technologies")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc0030" or addr[:6] == "fc0031" or addr[:6] == "fc0032" or addr[:6] == "fc0033":
|
|
all_addr.append(addr)
|
|
network.append("World: nFore Technology")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc0044" or addr[:6] == "fc0045" or addr[:6] == "fc0046" or addr[:6] == "fc0047":
|
|
all_addr.append(addr)
|
|
network.append("World: Digital Nordix AB (DNX)")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc0058" or addr[:6] == "fc0059" or addr[:6] == "fc005a" or addr[:6] == "fc005b":
|
|
all_addr.append(addr)
|
|
network.append("World: Schneider Electric")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc0060" or addr[:6] == "fc0061" or addr[:6] == "fc0062" or addr[:6] == "fc0063":
|
|
all_addr.append(addr)
|
|
network.append("World: ZENNER")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc0068" or addr[:6] == "fc0069" or addr[:6] == "fc006a" or addr[:6] == "fc006b":
|
|
all_addr.append(addr)
|
|
network.append("World: REQUEA")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc007c" or addr[:6] == "fc007d" or addr[:6] == "fc007e" or addr[:6] == "fc007f":
|
|
all_addr.append(addr)
|
|
network.append("World: mcf88 SRL")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc0084" or addr[:6] == "fc0085" or addr[:6] == "fc0086" or addr[:6] == "fc0087":
|
|
all_addr.append(addr)
|
|
network.append("World: Hiber")
|
|
activation.append("ABP")
|
|
elif addr[:6] == "fc0098" or addr[:6] == "fc0099" or addr[:6] == "fc009a" or addr[:6] == "fc009b":
|
|
all_addr.append(addr)
|
|
network.append("World: Mirakonta")
|
|
activation.append("ABP")
|
|
|
|
# Network prefix assignments to Australia
|
|
elif addr[:2] == "0a" or addr[:2] == "0b":
|
|
all_addr.append(addr)
|
|
network.append("Singapore Indonesia Australia Africa India: SingTel")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "46" or addr[:2] == "47":
|
|
all_addr.append(addr)
|
|
network.append("Australia New Zealand: Ventia")
|
|
activation.append("ABP")
|
|
elif addr[:2] == "58" or addr[:2] == "59":
|
|
all_addr.append(addr)
|
|
network.append("Australia: Airlora")
|
|
activation.append("ABP")
|
|
|
|
# Neither
|
|
else:
|
|
all_addr.append(addr)
|
|
other_addr.append(addr) # potential DevAddr from non-TTN network
|
|
network.append("-")
|
|
activation.append("-")
|
|
else:
|
|
all_addr.append("-")
|
|
network.append("-")
|
|
activation.append("-")
|
|
|
|
|
|
|
|
### Filtering the data for OTAA
|
|
print("3. Filtering the data for OTAA...")
|
|
info = every.payload
|
|
info = list(map(str, info))
|
|
deveuis = []
|
|
appeuis = []
|
|
deveui_revl = []
|
|
appeui_revl = []
|
|
deveui_len = 16
|
|
appeui_len = 16
|
|
|
|
for i in range(len(info)):
|
|
if list(map(str, mhdrs))[i] == "00":
|
|
deveui = info[i][20:38].split("-")
|
|
deveui = "".join(deveui)
|
|
appeui = info[i][2:20].split("-")
|
|
appeui = "".join(appeui)
|
|
deveuis.append(deveui)
|
|
appeuis.append(appeui)
|
|
else:
|
|
deveuis.append("-")
|
|
appeuis.append("-")
|
|
|
|
for row in deveuis: # reversing DevEUI's little endian form
|
|
fixed = []
|
|
for j in range(int(len(row)/2)):
|
|
fixed.append(row[j*2:(j+1)*2])
|
|
fixed.reverse()
|
|
deveui_rev = "".join(fixed)
|
|
deveui_revl.append(deveui_rev)
|
|
|
|
for row in appeuis: # reversing AppEUI's little endian form
|
|
fixed = []
|
|
for j in range(int(len(row)/2)):
|
|
fixed.append(row[j*2:(j+1)*2])
|
|
fixed.reverse()
|
|
appeui_rev = "".join(fixed)
|
|
appeui_revl.append(appeui_rev)
|
|
|
|
filt_deveui = [] # Remove payloads shorter than the length of DevAddr
|
|
filt_appeui = []
|
|
all_deveui = []
|
|
all_appeui = []
|
|
for deveui_s in deveui_revl:
|
|
if len(deveui_s) == deveui_len:
|
|
filt_deveui.append(deveui_s)
|
|
all_deveui.append(deveui_s)
|
|
else:
|
|
all_deveui.append("-")
|
|
|
|
for appeui_s in appeui_revl:
|
|
if len(appeui_s) == appeui_len:
|
|
filt_appeui.append(appeui_s)
|
|
all_appeui.append(appeui_s)
|
|
else:
|
|
all_appeui.append("-")
|
|
deveui_results = Counter(filt_deveui)
|
|
appeui_results = Counter(filt_appeui)
|
|
|
|
|
|
|
|
### Using API to obtain device manufacturer
|
|
print("4. Looking up device manufacturers...")
|
|
MAC_URL = "https://api.macvendors.com/v1/lookup/%s"
|
|
deveui_knowns = []
|
|
appeui_knowns = []
|
|
deveui_total = len(list(deveui_results.keys()))
|
|
appeui_total = len(list(appeui_results.keys()))
|
|
|
|
num = 1
|
|
starttime = time.time()
|
|
for eui in list(deveui_results.keys()):
|
|
print("Looking up", num, "out of", deveui_total, "DevEUIs...")
|
|
r = requests.get(MAC_URL % eui)
|
|
if "data" in list(r.json().keys()):
|
|
deveui_knowns.append([eui, r.json()])
|
|
num += 1
|
|
time.sleep(0.5)
|
|
|
|
num = 1
|
|
starttime = time.time()
|
|
for eui in list(appeui_results.keys()):
|
|
print("Looking up", num, "out of", appeui_total, "AppEUIs...")
|
|
r = requests.get(MAC_URL % eui)
|
|
if "data" in list(r.json().keys()):
|
|
appeui_knowns.append([eui, r.json()])
|
|
num += 1
|
|
time.sleep(0.5)
|
|
|
|
|
|
|
|
### Adding new columns
|
|
# Turn DevEUI and AppEUI knowns into dictionary
|
|
print("5. Adding new columns...")
|
|
deveui_knowns_dict = {}
|
|
appeui_knowns_dict = {}
|
|
for i in range(len(deveui_knowns)):
|
|
deveui_knowns_dict[deveui_knowns[i][0]] = deveui_knowns[i][1]
|
|
for i in range(len(appeui_knowns)):
|
|
appeui_knowns_dict[appeui_knowns[i][0]] = appeui_knowns[i][1]
|
|
|
|
# Get a list of devaddress and mic
|
|
devaddress = []
|
|
mic = []
|
|
for i in range(len(activation)):
|
|
if activation[i] != "-":
|
|
devaddress.append(devaddr_revl[i])
|
|
if len("".join(info[i].split("-"))[-8:]) == 8:
|
|
mic.append("".join(info[i].split("-"))[-8:])
|
|
else:
|
|
mic.append("-")
|
|
else:
|
|
devaddress.append(devaddr_revl[i])
|
|
if len("".join(info[i].split("-"))[-8:]) == 8:
|
|
mic.append("".join(info[i].split("-"))[-8:])
|
|
else:
|
|
mic.append("-")
|
|
|
|
# Create a dataframe for OTAA
|
|
dev_matcheui = []
|
|
app_matcheui = []
|
|
dev_manufeui = []
|
|
app_manufeui = []
|
|
manumac = []
|
|
for i in deveui_knowns:
|
|
dev_matcheui.append(i[0])
|
|
dev_manufeui.append(i[1].get("data").get("organization_name"))
|
|
manumac.append(i[1].get("data").get("assignment"))
|
|
|
|
for i in appeui_knowns:
|
|
app_matcheui.append(i[0])
|
|
app_manufeui.append(i[1].get("data").get("organization_name"))
|
|
|
|
#manufdf = pd.DataFrame({"DevEUI": dev_matcheui, "DevManufacturer": dev_manufeui, "MAC_prefix": manumac,
|
|
# "AppEUI": app_matcheui, "AppManufacturer": app_manufeui})
|
|
|
|
dictfilt = lambda x, y: dict([ (i,x[i]) for i in x if i in set(y) ])
|
|
deveui_res = dictfilt(deveui_results, dev_matcheui)
|
|
appeui_res = dictfilt(appeui_results, app_matcheui)
|
|
|
|
# Update the new columns' values
|
|
dev_manufid = []
|
|
app_manufid = []
|
|
for i in range(len(all_deveui)):
|
|
#if int(every["size"][i]) == 23 and str(mhdrs[i]) == "00":
|
|
if (all_deveui[i] in dev_matcheui or all_appeui[i] in app_matcheui) and str(mhdrs[i]) == "00":
|
|
activation[i] = "OTAA"
|
|
network[i] = "-"
|
|
devaddress[i] = all_deveui[i]
|
|
if all_deveui[i] in dev_matcheui and all_appeui[i] in app_matcheui:
|
|
dev_manufid.append(deveui_knowns_dict[all_deveui[i]].get("data").get("organization_name").replace(',', ''))
|
|
app_manufid.append(appeui_knowns_dict[all_appeui[i]].get("data").get("organization_name").replace(',', ''))
|
|
elif all_deveui[i] in dev_matcheui and all_appeui[i] not in app_matcheui:
|
|
dev_manufid.append(deveui_knowns_dict[all_deveui[i]].get("data").get("organization_name").replace(',', ''))
|
|
app_manufid.append("-")
|
|
elif all_deveui[i] not in dev_matcheui and all_appeui[i] in app_matcheui:
|
|
dev_manufid.append("-")
|
|
app_manufid.append(appeui_knowns_dict[all_appeui[i]].get("data").get("organization_name").replace(',', ''))
|
|
else:
|
|
dev_manufid.append("-")
|
|
app_manufid.append("-")
|
|
elif int(every["size"][i]) == 23 and str(mhdrs[i]) == "00":
|
|
activation[i] = "OTAA"
|
|
network[i] = "-"
|
|
devaddress[i] = all_deveui[i]
|
|
if all_deveui[i] in dev_matcheui and all_appeui[i] in app_matcheui:
|
|
dev_manufid.append(deveui_knowns_dict[all_deveui[i]].get("data").get("organization_name").replace(',', ''))
|
|
app_manufid.append(appeui_knowns_dict[all_appeui[i]].get("data").get("organization_name").replace(',', ''))
|
|
elif all_deveui[i] in dev_matcheui and all_appeui[i] not in app_matcheui:
|
|
dev_manufid.append(deveui_knowns_dict[all_deveui[i]].get("data").get("organization_name").replace(',', ''))
|
|
app_manufid.append("-")
|
|
elif all_deveui[i] not in dev_matcheui and all_appeui[i] in app_matcheui:
|
|
dev_manufid.append("-")
|
|
app_manufid.append(appeui_knowns_dict[all_appeui[i]].get("data").get("organization_name").replace(',', ''))
|
|
else:
|
|
dev_manufid.append("-")
|
|
app_manufid.append("-")
|
|
else:
|
|
dev_manufid.append("-")
|
|
app_manufid.append("-")
|
|
|
|
all_fcnt = []
|
|
all_fctrl = []
|
|
all_mhdr = []
|
|
final_appeui = []
|
|
for i in range(len(activation)):
|
|
if activation[i] == "ABP":
|
|
final_appeui.append("-")
|
|
all_mhdr.append(mhdrs[i])
|
|
all_fcnt.append(fcnt_revl[i])
|
|
all_fctrl.append(fctrls[i])
|
|
elif activation[i] == "-":
|
|
final_appeui.append("-")
|
|
all_fcnt.append(fcnt_revl[i])
|
|
all_fctrl.append(fctrls[i])
|
|
all_mhdr.append(mhdrs[i])
|
|
elif activation[i] == "OTAA":
|
|
final_appeui.append(all_appeui[i])
|
|
all_fcnt.append("-")
|
|
all_fctrl.append("-")
|
|
all_mhdr.append(mhdrs[i])
|
|
|
|
# Converting MHDR (hex) to binary and getting message type
|
|
mtype_raw = []
|
|
for hexdec in all_mhdr:
|
|
if hexdec == "-":
|
|
mtype_raw.append("-")
|
|
elif hexdec == "na":
|
|
mtype_raw.append("-")
|
|
elif hexdec == "9.":
|
|
mtype_raw.append("-")
|
|
else:
|
|
scale = 16 ## equals to hexadecimal
|
|
num_of_bits = 8
|
|
mtype_raw.append(str(bin(int(hexdec, scale))[2:].zfill(num_of_bits)[:3]))
|
|
|
|
mtype_desc = []
|
|
for mtype in mtype_raw:
|
|
if mtype == "000":
|
|
mtype_desc.append("Join-request")
|
|
elif mtype == "001":
|
|
mtype_desc.append("Join-accept")
|
|
elif mtype == "010":
|
|
mtype_desc.append("Unconfirmed Data Up")
|
|
elif mtype == "011":
|
|
mtype_desc.append("Unconfirmed Data Down")
|
|
elif mtype == "100":
|
|
mtype_desc.append("Confirmed Data Up")
|
|
elif mtype == "101":
|
|
mtype_desc.append("Confirmed Data Down")
|
|
elif mtype == "110":
|
|
mtype_desc.append("Rejoin-request")
|
|
elif mtype == "111":
|
|
mtype_desc.append("Proprietary")
|
|
else:
|
|
mtype_desc.append("-")
|
|
|
|
# Converting fcnt (hex) to decimal
|
|
int_fcnt = []
|
|
for fcnt_hex in all_fcnt:
|
|
if str(fcnt_hex) == "-":
|
|
int_fcnt.append("-")
|
|
elif str(fcnt_hex) == "":
|
|
int_fcnt.append("-")
|
|
else:
|
|
dec = int(fcnt_hex, 16)
|
|
int_fcnt.append(dec)
|
|
|
|
# Correcting the time
|
|
yr = []
|
|
month = []
|
|
day = []
|
|
hrs = []
|
|
mins = []
|
|
secs = []
|
|
for i in list(every["UTC timestamp"]):
|
|
#split for date and time
|
|
date_split = i.split(" ")
|
|
time_split = date_split[1].split(":")
|
|
|
|
if int(date_split[0].split("-")[0]) == 2013:
|
|
y = int(date_split[0].split("-")[0]) + 0
|
|
if len(str(y)) == 1:
|
|
yr.append("0"+str(y))
|
|
else:
|
|
yr.append(str(y))
|
|
m = int(date_split[0].split("-")[1]) - 0
|
|
if len(str(m)) == 1:
|
|
month.append("0"+str(m))
|
|
else:
|
|
month.append(str(m))
|
|
d = int(date_split[0].split("-")[2]) - 0
|
|
if len(str(d)) == 1:
|
|
day.append("0"+str(d))
|
|
else:
|
|
day.append(str(d))
|
|
h = int(time_split[0]) + 0
|
|
if len(str(h)) == 1:
|
|
hrs.append("0"+str(h))
|
|
else:
|
|
hrs.append(str(h))
|
|
m = int(time_split[1]) + 0
|
|
if len(str(m)) == 1:
|
|
mins.append("0"+str(m))
|
|
else:
|
|
mins.append(str(m))
|
|
secs.append(time_split[2])
|
|
|
|
elif int(date_split[0].split("-")[0]) == 2014:
|
|
y = int(date_split[0].split("-")[0]) + 0
|
|
if len(str(y)) == 1:
|
|
yr.append("0"+str(y))
|
|
else:
|
|
yr.append(str(y))
|
|
m = int(date_split[0].split("-")[1]) + 0
|
|
if len(str(m)) == 1:
|
|
month.append("0"+str(m))
|
|
else:
|
|
month.append(str(m))
|
|
d = int(date_split[0].split("-")[2]) + 0
|
|
if len(str(d)) == 1:
|
|
day.append("0"+str(d))
|
|
else:
|
|
day.append(str(d))
|
|
h = int(time_split[0]) + 0
|
|
if len(str(h)) == 1:
|
|
hrs.append("0"+str(h))
|
|
else:
|
|
hrs.append(str(h))
|
|
m = int(time_split[1]) + 0
|
|
if len(str(m)) == 1:
|
|
mins.append("0"+str(m))
|
|
else:
|
|
mins.append(str(m))
|
|
secs.append(time_split[2])
|
|
|
|
else:
|
|
yr.append(date_split[0].split("-")[0])
|
|
month.append(date_split[0].split("-")[1])
|
|
day.append(date_split[0].split("-")[2])
|
|
h = int(time_split[0]) + 0
|
|
if len(str(h)) == 1:
|
|
hrs.append("0"+str(h))
|
|
else:
|
|
hrs.append(str(h))
|
|
mins.append(time_split[1])
|
|
secs.append(time_split[2])
|
|
|
|
yr = list(map(str, yr))
|
|
month = list(map(str, month))
|
|
day = list(map(str, day))
|
|
hrs = list(map(str, hrs))
|
|
mins = list(map(str, mins))
|
|
secs = list(map(str, secs))
|
|
|
|
# correcting cases where mins >= 60 and hours >= 24
|
|
for i in range(len(mins)):
|
|
if int(mins[i]) >= 60:
|
|
h = int(hrs[i])
|
|
h += 1
|
|
if len(str(h)) == 1:
|
|
hrs[i] = "0"+str(h)
|
|
else:
|
|
hrs[i] = str(h)
|
|
m = int(mins[i])
|
|
m -= 60
|
|
if len(str(m)) == 1:
|
|
mins[i] = "0"+str(m)
|
|
else:
|
|
mins[i] = str(m)
|
|
|
|
for i in range(len(hrs)):
|
|
if int(hrs[i]) >= 24:
|
|
d = int(day[i])
|
|
d += 1
|
|
if len(str(d)) == 1:
|
|
day[i] = "0"+str(d)
|
|
else:
|
|
day[i] = str(d)
|
|
h = int(hrs[i])
|
|
h -= 24
|
|
if len(str(h)) == 1:
|
|
hrs[i] = "0"+str(h)
|
|
else:
|
|
hrs[i] = str(h)
|
|
|
|
# correcting cases where day is > possible value within a certain month
|
|
for i in range(len(day)):
|
|
if int(day[i]) > 30:
|
|
if month[i] in ["4", "6", "9", "11"]:
|
|
m = int(month[i])
|
|
m += 1
|
|
if len(str(m)) == 1:
|
|
month[i] = "0"+str(m)
|
|
else:
|
|
month[i] = str(m)
|
|
d = int(day[i])
|
|
d -= 30
|
|
if len(str(d)) == 1:
|
|
day[i] = "0"+str(d)
|
|
else:
|
|
day[i] = str(d)
|
|
elif int(day[i]) > 28:
|
|
if month[i] in ["2"]:
|
|
if int(yr[i])%4 == 0 and int(day[i]) > 29:
|
|
m = int(month[i])
|
|
m += 1
|
|
if len(str(m)) == 1:
|
|
month[i] = "0"+str(m)
|
|
else:
|
|
month[i] = str(m)
|
|
d = int(day[i])
|
|
d -= 29
|
|
if len(str(d)) == 1:
|
|
day[i] = "0"+str(d)
|
|
else:
|
|
day[i] = str(d)
|
|
elif int(yr[i])%4 != 0:
|
|
m = int(month[i])
|
|
m += 1
|
|
if len(str(m)) == 1:
|
|
month[i] = "0"+str(m)
|
|
else:
|
|
month[i] = str(m)
|
|
d = int(day[i])
|
|
d -= 28
|
|
if len(str(d)) == 1:
|
|
day[i] = "0"+str(d)
|
|
else:
|
|
day[i] = str(d)
|
|
|
|
# correcting cases where year needs to be changed
|
|
for i in range(len(month)):
|
|
if int(month[i]) == 12 and int(day[i]) > 31:
|
|
y = int(yr[i])
|
|
y += 1
|
|
yr[i] = str(y)
|
|
m = 1
|
|
if len(str(m)) == 1:
|
|
month[i] = "0"+str(m)
|
|
else:
|
|
month[i] = str(m)
|
|
d = 1
|
|
if len(str(d)) == 1:
|
|
day[i] = "0"+str(d)
|
|
else:
|
|
day[i] = str(d)
|
|
|
|
# concatenating the fixed date time
|
|
date = []
|
|
aus_time = []
|
|
|
|
for i in range(len(yr)):
|
|
date.append("-".join([yr[i], month[i], day[i]]))
|
|
aus_time.append(":".join([hrs[i], mins[i], secs[i]]))
|
|
|
|
every["date"] = date
|
|
every["time"] = aus_time
|
|
every["activation"] = activation
|
|
every["network"] = network
|
|
every["DevEUI or DevAddr"] = devaddress
|
|
every["AppEUI"] = final_appeui
|
|
every["fctrl"] = all_fctrl
|
|
every["fcnt"] = int_fcnt
|
|
every["mhdr"] = all_mhdr
|
|
every["mtype"] = mtype_raw
|
|
every["mtype_desc"] = mtype_desc
|
|
every["MIC"] = mic
|
|
every["deveui_manufacturer"] = dev_manufid
|
|
every["appeui_manufacturer"] = app_manufid
|
|
|
|
every = every[['UTC timestamp', 'date', 'time', 'us count', 'frequency', 'RF chain', 'RX chain','status',
|
|
'bandwidth', 'datarate', 'coderate', 'RSSI', 'SNR', 'size', 'DevEUI or DevAddr',
|
|
'AppEUI', 'fctrl', 'fcnt', 'mhdr', 'mtype', 'mtype_desc', 'MIC', 'activation',
|
|
'network', 'deveui_manufacturer', 'appeui_manufacturer', 'payload']]
|
|
|
|
filtered = every.copy()
|
|
no_fcnt = filtered.loc[(filtered.fcnt == "-") & (filtered.activation != "OTAA")].index
|
|
filtered = filtered.drop(no_fcnt)
|
|
|
|
|
|
|
|
### Calculating the time difference
|
|
# Function for truncating decimals without rounding to 3 dp
|
|
print("6. Calculating the time difference in seconds...")
|
|
time_sec = []
|
|
timeutc = list(pd.to_datetime(filtered["UTC timestamp"]))
|
|
for i in range(len(timeutc)):
|
|
time_sec.append(pd.Timedelta(timeutc[i]-timeutc[0]).total_seconds())
|
|
|
|
# Add a new column to the dataframe
|
|
filtered["sec_diff"] = time_sec
|
|
|
|
|
|
|
|
### Algorithm for identifying unique devices
|
|
# Split it from the original dataframe by DevAddr or DevEUI
|
|
print("7. Identifying unique devices...")
|
|
l_freq = []
|
|
l_devaddr915 = []
|
|
l_devaddr923 = []
|
|
all_freq = []
|
|
filtered = filtered.loc[filtered.status == "CRC_OK "]
|
|
|
|
# ISM band
|
|
fr915 = [916800000, 917000000, 917200000, 917400000, 917600000, 917800000, 918000000, 91820000]
|
|
fr923 = [922000000, 922100000, 922200000, 922400000, 922600000, 922800000, 923000000, 923200000, 923400000]
|
|
|
|
freq915 = filtered.loc[filtered.frequency.isin(fr915)]
|
|
if freq915.shape[0] > 0:
|
|
freq915 = filtered.loc[filtered.frequency.isin(fr915)].index
|
|
filtered.loc[freq915, "Freq_Plan"] = "915band"
|
|
all_freq.append(freq915)
|
|
|
|
freq923 = filtered.loc[filtered.frequency.isin(fr923)]
|
|
if freq923.shape[0] > 0:
|
|
freq923 = filtered.loc[filtered.frequency.isin(fr923)].index
|
|
filtered.loc[freq923, "Freq_Plan"] = "923band"
|
|
all_freq.append(freq923)
|
|
|
|
if len(all_freq) == 0:
|
|
print("ERROR: No valid LoRaWAN packets!")
|
|
exit()
|
|
|
|
if (freq915.shape[0] and freq923.shape[0]) > 0:
|
|
for a, b in filtered.groupby("Freq_Plan", sort=False):
|
|
l_freq.append(b.sort_values(by=["sec_diff"]))
|
|
#915
|
|
for a, b in l_freq[0].groupby("DevEUI or DevAddr", sort=False):
|
|
l_devaddr915.append(b.sort_values(by=["sec_diff"]))
|
|
#923
|
|
for a, b in l_freq[1].groupby("DevEUI or DevAddr", sort=False):
|
|
l_devaddr923.append(b.sort_values(by=["sec_diff"]))
|
|
|
|
elif freq915.shape[0] == 0:
|
|
#923
|
|
for a, b in filtered.groupby("DevEUI or DevAddr", sort=False):
|
|
l_devaddr923.append(b.sort_values(by=["sec_diff"]))
|
|
|
|
elif freq923.shape[0] == 0:
|
|
#915
|
|
for a, b in filtered.groupby("DevEUI or DevAddr", sort=False):
|
|
l_devaddr915.append(b.sort_values(by=["sec_diff"]))
|
|
|
|
|
|
### Counting the number of devices
|
|
print("8. Counting the number of devices...")
|
|
def truncate(f):
|
|
if f == "-":
|
|
return "-"
|
|
else:
|
|
return math.floor(f * 10 ** 3) / 10 ** 3
|
|
|
|
def truncate3(f):
|
|
if f == "-":
|
|
return "-"
|
|
else:
|
|
return math.floor(f * 10 ** 3) / 10 ** 3
|
|
|
|
def truncate0(f):
|
|
if f == "-":
|
|
return "-"
|
|
else:
|
|
return math.floor(f * 10 ** 0) / 10 ** 0
|
|
|
|
dev_num915 = []
|
|
rate915 = []
|
|
dev_num923 = []
|
|
rate923 = []
|
|
num = 1
|
|
|
|
# Identifying unique devices
|
|
l_index_915 = []
|
|
if len(l_devaddr915) > 0:
|
|
for i in l_devaddr915:
|
|
sec_df = list(map(float, i["sec_diff"]))
|
|
sec_df = [x - sec_df[0] for x in sec_df]
|
|
sec_df = list(map(truncate, sec_df))
|
|
|
|
devaddr_df = list(i["DevEUI or DevAddr"])
|
|
activation_df = list(i["activation"])
|
|
|
|
# OTAA case
|
|
if activation_df[0] == "OTAA":
|
|
l_index_915.extend(i.index)
|
|
for j in range(len(devaddr_df)):
|
|
if j >= 1:
|
|
rate915.append(truncate3(float(sec_df[j]) - float(sec_df[j-1])))
|
|
else:
|
|
rate915.append("-")
|
|
dev_num915.extend(repeat(num, len(devaddr_df)))
|
|
num += 1
|
|
|
|
# ABP case
|
|
# Single packet case
|
|
elif i.shape[0] == 1 and activation_df[0] != "OTAA":
|
|
l_index_915.extend(i.index)
|
|
dev_num915.append(num)
|
|
rate915.append("-")
|
|
num += 1
|
|
|
|
# 2 packets or more
|
|
elif i.shape[0] > 1 and activation_df[0] == "ABP":
|
|
dev_num915.extend(repeat(num, i.shape[0]))
|
|
#j = i.sort_values(by=["date", "time"]) # sort by date and time
|
|
l_index_915.extend(i.index)
|
|
fcnt_df = list(map(int, i["fcnt"]))
|
|
i_rate = []
|
|
rate915.append("-")
|
|
|
|
for k in range(len(fcnt_df)): # +1 to start from 2nd row
|
|
if 1 <= k < len(fcnt_df): # make sure it doesn't exceed the row index limit
|
|
if fcnt_df[k] != fcnt_df[k-1]:
|
|
i_rate.append(truncate3(((sec_df[k] - sec_df[k-1])/(fcnt_df[k] - fcnt_df[k-1]))))
|
|
else:
|
|
i_rate.append(truncate3((sec_df[k] - sec_df[k-1])))
|
|
trunc_i_rate = []
|
|
i_rate2 = list(map(np.round, i_rate))
|
|
i_rate_set = list(dict.fromkeys(i_rate2)) # list of the set intervals to look up for assigning devnumber
|
|
# Remove rates that are within +-1 rate of each other
|
|
for m in range(len(i_rate_set)):
|
|
if m == 0:
|
|
trunc_i_rate.append(i_rate_set[m])
|
|
elif m >= 1:
|
|
if (i_rate_set[m] > all([x+1 for x in trunc_i_rate])) or (i_rate_set[m] < all([x-1 for x in trunc_i_rate])):
|
|
trunc_i_rate.append(i_rate_set[m])
|
|
|
|
for element in i_rate:
|
|
for i_devnum in range(len(trunc_i_rate)):
|
|
if (trunc_i_rate[i_devnum] - 1) <= float(element) <= (trunc_i_rate[i_devnum] + 1):
|
|
break
|
|
else:
|
|
continue
|
|
rate915.append(element)
|
|
num += 1
|
|
|
|
# For neither OTAA and ABP activation and more than 1 packet
|
|
elif i.shape[0] > 1 and activation_df[0] == "-":
|
|
dev_num915.extend(repeat(num, i.shape[0]))
|
|
#j = i.sort_values(by=["date", "time"]) # sort by date and time
|
|
l_index_915.extend(i.index)
|
|
fcnt_df = list(i["fcnt"])
|
|
if any(i["fcnt"] == "-"):
|
|
for k in range(len(fcnt_df)): # +1 to start from 2nd row
|
|
if 1 <= k < len(fcnt_df): # make sure it doesn't exceed the row index limit
|
|
rate915.append(truncate3((sec_df[k] - sec_df[k-1])))
|
|
else:
|
|
fcnt_df = list(map(int, i["fcnt"]))
|
|
i_rate = []
|
|
rate915.append("-")
|
|
|
|
for k in range(len(fcnt_df)): # +1 to start from 2nd row
|
|
if 1 <= k < len(fcnt_df): # make sure it doesn't exceed the row index limit
|
|
if fcnt_df[k] != fcnt_df[k-1]:
|
|
i_rate.append(truncate3(((sec_df[k] - sec_df[k-1])/(fcnt_df[k] - fcnt_df[k-1]))))
|
|
else:
|
|
i_rate.append(truncate3((sec_df[k] - sec_df[k-1])))
|
|
trunc_i_rate = []
|
|
i_rate2 = list(map(np.round, i_rate))
|
|
i_rate_set = list(dict.fromkeys(i_rate2)) # list of the set intervals to look up for assigning devnumber
|
|
# Remove rates that are within +-1 rate of each other
|
|
for m in range(len(i_rate_set)):
|
|
if m == 0:
|
|
trunc_i_rate.append(i_rate_set[m])
|
|
elif m >= 1:
|
|
if (i_rate_set[m] > all([x+1 for x in trunc_i_rate])) or (i_rate_set[m] < all([x-1 for x in trunc_i_rate])):
|
|
trunc_i_rate.append(i_rate_set[m])
|
|
|
|
for element in i_rate:
|
|
for i_devnum in range(len(trunc_i_rate)):
|
|
if (trunc_i_rate[i_devnum] - 1) <= float(element) <= (trunc_i_rate[i_devnum] + 1):
|
|
break
|
|
else:
|
|
continue
|
|
rate915.append(element)
|
|
num += 1
|
|
|
|
l_index_923 = []
|
|
if len(l_devaddr923) > 0:
|
|
for i in l_devaddr923:
|
|
sec_df = list(map(float, i["sec_diff"]))
|
|
sec_df = [x - sec_df[0] for x in sec_df]
|
|
sec_df = list(map(truncate, sec_df))
|
|
|
|
devaddr_df = list(i["DevEUI or DevAddr"])
|
|
activation_df = list(i["activation"])
|
|
|
|
# OTAA case
|
|
if activation_df[0] == "OTAA":
|
|
l_index_923.extend(i.index)
|
|
for j in range(len(devaddr_df)):
|
|
if j >= 1:
|
|
rate923.append(truncate3(float(sec_df[j]) - float(sec_df[j-1])))
|
|
else:
|
|
rate923.append("-")
|
|
dev_num923.extend(repeat(num, len(devaddr_df)))
|
|
num += 1
|
|
|
|
# ABP case
|
|
# Single packet case
|
|
elif i.shape[0] == 1 and activation_df[0] != "OTAA":
|
|
l_index_923.extend(i.index)
|
|
dev_num923.append(num)
|
|
rate923.append("-")
|
|
num += 1
|
|
|
|
# 2 packets or more
|
|
elif i.shape[0] > 1 and activation_df[0] == "ABP":
|
|
dev_num923.extend(repeat(num, i.shape[0]))
|
|
#j = i.sort_values(by=["date", "time"]) # sort by date and time
|
|
l_index_923.extend(i.index)
|
|
fcnt_df = list(map(int, i["fcnt"]))
|
|
i_rate = []
|
|
rate923.append("-")
|
|
|
|
for k in range(len(fcnt_df)): # +1 to start from 2nd row
|
|
if 1 <= k < len(fcnt_df): # make sure it doesn't exceed the row index limit
|
|
if fcnt_df[k] != fcnt_df[k-1]:
|
|
i_rate.append(truncate3(((sec_df[k] - sec_df[k-1])/(fcnt_df[k] - fcnt_df[k-1]))))
|
|
else:
|
|
i_rate.append(truncate3((sec_df[k] - sec_df[k-1])))
|
|
trunc_i_rate = []
|
|
i_rate2 = list(map(np.round, i_rate))
|
|
i_rate_set = list(dict.fromkeys(i_rate2)) # list of the set intervals to look up for assigning devnumber
|
|
# Remove rates that are within +-1 rate of each other
|
|
for m in range(len(i_rate_set)):
|
|
if m == 0:
|
|
trunc_i_rate.append(i_rate_set[m])
|
|
elif m >= 1:
|
|
if (i_rate_set[m] > all([x+1 for x in trunc_i_rate])) or (i_rate_set[m] < all([x-1 for x in trunc_i_rate])):
|
|
trunc_i_rate.append(i_rate_set[m])
|
|
|
|
for element in i_rate:
|
|
for i_devnum in range(len(trunc_i_rate)):
|
|
if (trunc_i_rate[i_devnum] - 1) <= float(element) <= (trunc_i_rate[i_devnum] + 1):
|
|
break
|
|
else:
|
|
continue
|
|
rate923.append(element)
|
|
num += 1
|
|
|
|
# For neither OTAA and ABP activation and more than 1 packet
|
|
elif i.shape[0] > 1 and activation_df[0] == "-":
|
|
dev_num923.extend(repeat(num, i.shape[0]))
|
|
#j = i.sort_values(by=["date", "time"]) # sort by date and time
|
|
l_index_923.extend(i.index)
|
|
fcnt_df = list(i["fcnt"])
|
|
if any(i["fcnt"] == "-"):
|
|
for k in range(len(fcnt_df)): # +1 to start from 2nd row
|
|
if 1 <= k < len(fcnt_df): # make sure it doesn't exceed the row index limit
|
|
rate923.append(truncate3((sec_df[k] - sec_df[k-1])))
|
|
else:
|
|
fcnt_df = list(map(int, i["fcnt"]))
|
|
i_rate = []
|
|
rate923.append("-")
|
|
|
|
for k in range(len(fcnt_df)): # +1 to start from 2nd row
|
|
if 1 <= k < len(fcnt_df): # make sure it doesn't exceed the row index limit
|
|
if fcnt_df[k] != fcnt_df[k-1]:
|
|
i_rate.append(truncate3(((sec_df[k] - sec_df[k-1])/(fcnt_df[k] - fcnt_df[k-1]))))
|
|
else:
|
|
i_rate.append(truncate3((sec_df[k] - sec_df[k-1])))
|
|
trunc_i_rate = []
|
|
i_rate2 = list(map(np.round, i_rate))
|
|
i_rate_set = list(dict.fromkeys(i_rate2)) # list of the set intervals to look up for assigning devnumber
|
|
# Remove rates that are within +-1 rate of each other
|
|
for m in range(len(i_rate_set)):
|
|
if m == 0:
|
|
trunc_i_rate.append(i_rate_set[m])
|
|
elif m >= 1:
|
|
if (i_rate_set[m] > all([x+1 for x in trunc_i_rate])) or (i_rate_set[m] < all([x-1 for x in trunc_i_rate])):
|
|
trunc_i_rate.append(i_rate_set[m])
|
|
|
|
for element in i_rate:
|
|
for i_devnum in range(len(trunc_i_rate)):
|
|
if (trunc_i_rate[i_devnum] - 1) <= float(element) <= (trunc_i_rate[i_devnum] + 1):
|
|
break
|
|
else:
|
|
continue
|
|
rate923.append(element)
|
|
num += 1
|
|
|
|
|
|
|
|
### Sort the derived device number, interval, rate by their corresponding index (to match it with original dataframe)
|
|
print("9. Sorting the device numbers by index...")
|
|
def sortFirst(val):
|
|
return val[0]
|
|
|
|
all_l_indx = []
|
|
rate = []
|
|
dev_num = []
|
|
|
|
if len(l_devaddr915) > 0:
|
|
all_list915 = list(zip(l_index_915, rate915, dev_num915))
|
|
all_list915.sort(key = sortFirst)
|
|
|
|
for i in all_list915:
|
|
all_l_indx.append(i[0])
|
|
rate.append(i[1])
|
|
dev_num.append(i[2])
|
|
|
|
elif len(l_devaddr) > 0:
|
|
all_list923 = list(zip(l_index_923, rate923, dev_num923))
|
|
all_list923.sort(key = sortFirst)
|
|
|
|
for i in all_list923:
|
|
all_l_indx.append(i[0])
|
|
rate.append(i[1])
|
|
dev_num.append(i[2])
|
|
|
|
all_list = list(zip(all_l_indx, rate, dev_num))
|
|
all_list.sort(key = sortFirst)
|
|
|
|
|
|
### Adding the corrected ordered tx_interval and dev_number to the dataframe
|
|
print("10. Adding the transmission interval column...")
|
|
l_rate = []
|
|
l_dev_num = []
|
|
for i in all_list:
|
|
if i[1] != "-":
|
|
l_rate.append(float(i[1]))
|
|
l_dev_num.append(int(i[2]))
|
|
else:
|
|
l_rate.append(i[1])
|
|
l_dev_num.append(int(i[2]))
|
|
|
|
filtered["tx_interval"] = l_rate
|
|
filtered["dev_number"] = l_dev_num
|
|
|
|
|
|
|
|
### Save as csv
|
|
print("11. Saving as csv...")
|
|
filtered.to_csv(pd.datetime.today().strftime('%y%m%d_%H%M%S_') + "LoRadar_data.csv", index=False)
|
|
print("Data saved!")
|