Allow replaying traffic from file
This commit is contained in:
parent
659525cefb
commit
1c4bf3e340
@ -6,13 +6,12 @@ import numpy.typing as npt
|
|||||||
import typer
|
import typer
|
||||||
|
|
||||||
from .. import visualise
|
from .. import visualise
|
||||||
from ..collection import ingest
|
|
||||||
from ..config import config
|
from ..config import config
|
||||||
from ..processing.aoa import AoA
|
from ..processing.aoa import AoA
|
||||||
from ..processing.preprocess import Preprocessor
|
from ..processing.preprocess import Preprocessor
|
||||||
from . import file
|
from . import file, globals
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer(callback=globals.main)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -27,6 +26,9 @@ def antennas() -> None:
|
|||||||
"""
|
"""
|
||||||
from ..utils import antenna_order
|
from ..utils import antenna_order
|
||||||
|
|
||||||
|
if not globals.is_live:
|
||||||
|
raise ValueError("This command only works with live data")
|
||||||
|
|
||||||
antenna_order.main()
|
antenna_order.main()
|
||||||
|
|
||||||
|
|
||||||
@ -48,7 +50,8 @@ def heatmap() -> None:
|
|||||||
if not webapp_queue.full():
|
if not webapp_queue.full():
|
||||||
webapp_queue.put(aoa)
|
webapp_queue.put(aoa)
|
||||||
|
|
||||||
ingest.start_processing(callback)
|
globals.csi_producer(csi_callback=callback)
|
||||||
|
logger.info("Finished processing CSI data")
|
||||||
|
|
||||||
|
|
||||||
app.add_typer(file.app, name="file", help="Commands for working with CSI files")
|
app.add_typer(file.app, name="file", help="Commands for working with CSI files")
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import numpy as np
|
|||||||
import numpy.typing as npt
|
import numpy.typing as npt
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
from ..collection import ingest
|
from . import globals
|
||||||
|
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer()
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@ -24,17 +25,4 @@ def capture(output_path: Path) -> None:
|
|||||||
logger.info(f"Got final CSI data with shape {antenna_data.shape}")
|
logger.info(f"Got final CSI data with shape {antenna_data.shape}")
|
||||||
file.create_dataset(datetime.now().isoformat(), data=antenna_data)
|
file.create_dataset(datetime.now().isoformat(), data=antenna_data)
|
||||||
|
|
||||||
ingest.start_processing(callback)
|
globals.csi_producer(csi_callback=callback)
|
||||||
|
|
||||||
|
|
||||||
@app.command()
|
|
||||||
def replay(input_path: Path) -> None:
|
|
||||||
"""Replay CSI data from a file"""
|
|
||||||
logger.info(f"Replaying data from {input_path}")
|
|
||||||
|
|
||||||
start_time = datetime.now()
|
|
||||||
|
|
||||||
with h5py.File(input_path, "r") as file:
|
|
||||||
for key in file:
|
|
||||||
logger.info(f"Sending data from {key}")
|
|
||||||
ingest.send_data(file[key][:])
|
|
||||||
|
|||||||
18
src/cli/globals.py
Normal file
18
src/cli/globals.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
from functools import partial
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from .. import collection
|
||||||
|
from ..collection import file, ingest
|
||||||
|
|
||||||
|
csi_producer: collection.CSIProducer = collection.noop
|
||||||
|
is_live = True
|
||||||
|
|
||||||
|
|
||||||
|
def main(from_file: Path | None = None) -> None:
|
||||||
|
global csi_producer, is_live
|
||||||
|
if from_file:
|
||||||
|
csi_producer = partial(file.start_processing, file_path=from_file)
|
||||||
|
is_live = False
|
||||||
|
else:
|
||||||
|
csi_producer = ingest.start_processing
|
||||||
|
is_live = True
|
||||||
9
src/collection/__init__.py
Normal file
9
src/collection/__init__.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from . import file, ingest
|
||||||
|
from .protocols import CSICallback, CSIProducer
|
||||||
|
|
||||||
|
|
||||||
|
def noop(csi_callback: CSICallback | None = None) -> None:
|
||||||
|
del csi_callback
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["file", "ingest", "noop", "CSIProducer", "CSICallback"]
|
||||||
39
src/collection/file.py
Normal file
39
src/collection/file.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import h5py
|
||||||
|
|
||||||
|
from . import protocols
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def start_processing(
|
||||||
|
file_path: Path,
|
||||||
|
csi_callback: protocols.CSICallback | None = None,
|
||||||
|
) -> None:
|
||||||
|
logger.info(f"Replaying CSI data from {file_path}")
|
||||||
|
with h5py.File(file_path, "r") as file:
|
||||||
|
try:
|
||||||
|
for key in file:
|
||||||
|
datetime.fromisoformat(key)
|
||||||
|
except ValueError as e:
|
||||||
|
logger.exception(
|
||||||
|
"The file provided was not generated using this software", e
|
||||||
|
)
|
||||||
|
|
||||||
|
start_time = datetime.fromisoformat(list(file.keys())[0])
|
||||||
|
target_offset = datetime.now() - start_time
|
||||||
|
for key in file:
|
||||||
|
logger.debug(f"Sending data from {key} at {datetime.now().isoformat()}")
|
||||||
|
csi_callback(file[key][:])
|
||||||
|
curr_time_virtual = datetime.fromisoformat(key)
|
||||||
|
new_offset = datetime.now() - curr_time_virtual
|
||||||
|
logger.debug(f"New offset {new_offset}, target is {target_offset}")
|
||||||
|
if new_offset > target_offset + timedelta(seconds=1):
|
||||||
|
logger.warning(
|
||||||
|
f"Data is {new_offset - target_offset} behind, lagging behind..."
|
||||||
|
)
|
||||||
|
time.sleep(max(0, (target_offset - new_offset).total_seconds()))
|
||||||
@ -9,13 +9,12 @@ from datetime import datetime
|
|||||||
from typing import Callable, NamedTuple
|
from typing import Callable, NamedTuple
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import numpy.typing as npt
|
|
||||||
|
|
||||||
from ..config import config
|
from ..config import config
|
||||||
from .csi_frame import CSI
|
from .csi_frame import CSI
|
||||||
|
from .protocols import CSICallback
|
||||||
|
|
||||||
Host = tuple[str, int]
|
Host = tuple[str, int]
|
||||||
CSICallback = Callable[[npt.NDArray[np.complex128]], None]
|
|
||||||
|
|
||||||
|
|
||||||
class FeitHost:
|
class FeitHost:
|
||||||
|
|||||||
10
src/collection/protocols.py
Normal file
10
src/collection/protocols.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from typing import Callable, Protocol
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import numpy.typing as npt
|
||||||
|
|
||||||
|
CSICallback = Callable[[npt.NDArray[np.complex128]], None]
|
||||||
|
|
||||||
|
|
||||||
|
class CSIProducer(Protocol):
|
||||||
|
def __call__(self, csi_callback: CSICallback | None = None) -> None: ...
|
||||||
@ -28,12 +28,12 @@ def callback(antenna_data: dict[ingest.Host, ingest.CSI]) -> None:
|
|||||||
)
|
)
|
||||||
for host, csi in antenna_data.items():
|
for host, csi in antenna_data.items():
|
||||||
antenna_average[(host, 0)] = (
|
antenna_average[(host, 0)] = (
|
||||||
antenna_average.get((host, 0), csi.header.rssi1) * 0.9
|
antenna_average.get((host, 0), csi.header.rssi1) * 0.99
|
||||||
+ csi.header.rssi1 * 0.1
|
+ csi.header.rssi1 * 0.01
|
||||||
)
|
)
|
||||||
antenna_average[(host, 1)] = (
|
antenna_average[(host, 1)] = (
|
||||||
antenna_average.get((host, 1), csi.header.rssi2) * 0.9
|
antenna_average.get((host, 1), csi.header.rssi2) * 0.99
|
||||||
+ csi.header.rssi2 * 0.1
|
+ csi.header.rssi2 * 0.01
|
||||||
)
|
)
|
||||||
if csi.header.rssi1 > antenna_average[(host, 0)] + RSSI_THRESHOLD:
|
if csi.header.rssi1 > antenna_average[(host, 0)] + RSSI_THRESHOLD:
|
||||||
unplugged.add((host, 0))
|
unplugged.add((host, 0))
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user