This commit is contained in:
Paweł Sadowski 2024-12-17 09:54:03 +00:00
parent 24b3a90520
commit e10661be5e
4 changed files with 308 additions and 0 deletions

22
logger.py Normal file
View File

@ -0,0 +1,22 @@
from datetime import datetime
from colorist import Color
STYLE_DEFAULT = Color.WHITE
def log_time():
return datetime.now().strftime("%H:%M:%S.%f")[:-3]
def log_time_name():
return datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
log_file = open(f'logs/L-{log_time_name()}.txt', 'a')
def spr(x, style=STYLE_DEFAULT):
print(f"[{log_time()}] {style}{x}{Color.OFF}")
log_file.write(f'[{log_time()}] {x}\n')
def prefixed_spr(prefix, pr=spr):
def ret(x, *args):
pr(f"{prefix}: {x}", *args)
return ret

91
measurement_station.py Normal file
View File

@ -0,0 +1,91 @@
import asyncio
from collections.abc import Iterable, Sequence
from dataclasses import dataclass
from logging import debug
import logging
from logger import spr
import thrust_stand
import norsonic
from norsonic_fetcher import nor_get_reports, recording_path
from thrust_stand import ThrustStand, ThrustStandMeasurement
@dataclass
class OpPointData:
data_thrust_stand: Sequence[ThrustStandMeasurement]
data_accustic: dict
@property
def data_thrust_stand_avg(self):
return sum(self.data_thrust_stand, ThrustStandMeasurement.zero())/len(self.data_thrust_stand)
@property
def data_accustic_avg(self):
return {k: sum(map(float, (row[k] for row in self.data_accustic)))/len(self.data_accustic) for k in self.data_accustic[0].keys() if k != 'Date'}
@dataclass
class ConnectionParams:
stand_tty: str
nor_addr: str
nor_ftp_user: str
nor_ftp_pass: str
nor_recordings_dir: str
CONN_PARAMS = ConnectionParams(
stand_tty='/dev/ttyUSB0',
nor_addr='10.145.1.1',
nor_ftp_user='AAAA',
nor_ftp_pass='1234',
nor_recordings_dir='/SD Card/NorMeas/Nor14530408/TEST'
)
async def meas_series(params: ConnectionParams, pwms: Iterable[int]):
stand = await ThrustStand.open_connection(params.stand_tty)
nor = await norsonic.open_connection(params.nor_addr)
results_stand = {}
files_nor = {}
# TODO TARA
sample, = stand.get_samples_raw(1)
stand.tare_thrust = thrust_stand.raw_thrust(sample.load_thrust)
stand.tare_torque = thrust_stand.raw_torque(sample.load_left, sample.load_right)
for pwm in pwms:
stand.mot_pwm = pwm
spr(f'Output: {pwm}PWM')
await stand.stabilize_rpm(5, 1)
spr(f'Starting measurement')
stand_series_pending = stand.start_meas_series()
files_nor[pwm] = await norsonic.record(nor)
spr(f'Done')
results_stand[pwm] = stand.finish_meas_series(stand_series_pending)
stand.mot_pwm = 1000
await asyncio.sleep(3)
spr('Downlaoding reports')
nor_reports = await nor_get_reports(params.nor_addr, params.nor_ftp_user, params.nor_ftp_pass, [files_nor[pwm] for pwm in pwms])
spr('Done')
ret = {
pwm: OpPointData(
data_thrust_stand=results_stand[pwm],
data_accustic=nor_reports[i]
) for i, pwm in enumerate(pwms)
}
return ret
async def main():
global x
x = await meas_series(CONN_PARAMS, range(1100, 1950, 30))
# logging.basicConfig(level=logging.INFO)
# asyncio.run(main(), debug=True)

105
norsonic.py Normal file
View File

@ -0,0 +1,105 @@
import asyncio
from collections.abc import Callable, Iterable, Sequence
from typing import Optional
from urllib import parse
import aioftp
import websockets
from websockets.asyncio.client import ClientConnection
from logger import spr
import norsonic_fetcher
MSG_OUT_NEW = "NewMeasurement"
MSG_OUT_START = "StartMeasurement"
KEY_STATE = 'State'
KEY_FILENAME = 'GraphHeader'
VAL_STATE_NEW = ''
VAL_STATE_RECORDING = "<span title='Running' class='icon-play4 greenFg'></span>"
VAL_STATE_WAITING = "<span title='Waiting' class='icon-busy'></span>"
VAL_STATE_DONE = "<span title='Saved' class='icon-disk'></span>"
def parse_msg(msg: str) -> dict[str, str]:
ret = {}
for l in msg.splitlines():
# print(f'par "{l}"')
if len(l) == 0:
continue
if l == 'clear':
break
if ':' not in l:
print(f'W: Unexpected line in message: {l}')
continue
k, v = l.split(':', 1)
if k in ret:
if ret[k] == v:
continue
if len(v) == 0:
continue
print(f'W: Duplicate key detected ({k}: {v})')
raise RuntimeError()
ret[k] = v
return ret
class NSWSConnection:
# def __init__(self, ws: Web)
...
async def recv_msg(sock: ClientConnection) -> dict[str, str]:
recv = await sock.recv()
if not isinstance(recv, str):
raise RuntimeError('Invalid message received')
msg = parse_msg(recv)
return msg
async def wait_for_state(sock: ClientConnection, state: str, expected_states: Iterable[str] = []) -> dict[str, str]:
while True:
msg = await recv_msg(sock)
# spr(msg)
if KEY_STATE in msg:
if msg[KEY_STATE] == state:
return msg
elif msg[KEY_STATE] not in expected_states:
spr(f'W: Unexpected state received: {msg[KEY_STATE]}')
async def record(sock: ClientConnection, start_callback: Optional[Callable[[], None]] = None):
await sock.send(MSG_OUT_NEW)
spr('Initializing measurement')
await wait_for_state(sock, VAL_STATE_NEW, (VAL_STATE_DONE, ))
await sock.send(MSG_OUT_START)
spr('Starting measurement')
await wait_for_state(sock, VAL_STATE_WAITING, (VAL_STATE_NEW, ))
spr('Waiting for start')
await wait_for_state(sock, VAL_STATE_RECORDING)
if start_callback is not None:
start_callback()
spr('Waiting for finish')
msg = await wait_for_state(sock, VAL_STATE_DONE)
return msg[KEY_FILENAME]
async def open_connection(address: str) -> ClientConnection:
return await websockets.connect(f'ws://{address}/live', ping_interval=None)
# async def main():
# sock = await websockets.connect('ws://10.145.1.1/live')
# spr('Connected to server')
# name = await record(sock)
# spr(f'finished {name}')
# c = aioftp.Client(parse_list_line_custom=norsonic_fetcher.ftp_parse_line)
# res = await c.connect('10.145.1.1')
# res = await c.login('AAAA', '1234')
# global x
# # x = norsonic_fetcher.parse_report(await norsonic_fetcher.ftp_fetch(c, norsonic_fetcher.recording_path(name)))
# x = norsonic_fetcher.parse_report(await norsonic_fetcher.ftp_fetch(c, norsonic_fetcher.FNAME))
# print(x)

90
norsonic_fetcher.py Normal file
View File

@ -0,0 +1,90 @@
import asyncio
from pathlib import Path
from re import split
from typing import Iterable, Sequence
import aioftp
from logger import spr
FNAME = '/SD Card/NorMeas/Nor14530408/TEST/VIP 124 2024-12-10 15-31-19/VIP 124 2024-12-10 15-31-19.txt'
DNAME = '/SD Card/NorMeas/Nor14530408/TEST/VIP 124 2024-12-10 15-31-19/'
RECORDINGS_PATH = '/SD Card/NorMeas/Nor14530408/TEST'
CRLF = '\r\n'
COL_SEPARATOR = '\t'
STR_DIR = '<DIR>'
def recording_path(rec_name: str) -> str:
return f'{RECORDINGS_PATH}/{rec_name}/{rec_name}.txt'
def ftp_parse_line(line: bytes):
l = line.decode()
date, time, size, name = l.split(None, 3)
_ = date
_ = time
attrdict = {'modify': None, 'size': 0, 'type': 'dir'}
if size != STR_DIR:
attrdict['type'] = 'file'
attrdict['size'] = int(size)
if not name.endswith(CRLF):
raise ValueError()
name = name[:-2]
path = Path(name)
return path, attrdict
async def ftp_fetch(client: aioftp.Client, path: str) -> bytes:
spr(f'fetching {path}')
stream = await client.download_stream(path)
file = b''.join([block async for block in stream.iter_by_block()])
await stream.finish()
stream.close()
return file
def parse_report_table(table: str):
_, head_cols, *rows = table.split(CRLF)
cols = head_cols.split(COL_SEPARATOR)
def parse_row(row: str):
vals = row.split(COL_SEPARATOR)
if len(vals) != len(cols):
print(vals)
print(cols)
print(len(cols))
print(len(vals))
raise ValueError('NorPaeser: Invalid row read')
return {cols[i]: vals[i] for i in range(len(cols))}
return [parse_row(r) for r in rows if len(r) > 0]
def parse_report(report: bytes):
*header, glob, prof = report.decode().split(2*CRLF)
t_prof = parse_report_table(prof)
# t_glob = parse_report_table(glob)
# return t_glob, t_prof
return t_prof
async def nor_get_reports(addr: str, user: str, password: str, recs: Iterable[str]) -> Sequence:
async with aioftp.Client.context(addr, user=user, password=password, parse_list_line_custom=ftp_parse_line) as ftp:
return [parse_report(await ftp_fetch(ftp, recording_path(p))) for p in recs]
async def main():
c = aioftp.Client(parse_list_line_custom=ftp_parse_line)
res = await c.connect('10.145.1.1')
res = await c.login('AAAA', '1234')
global x
ns = [
'VIP 197 2024-12-13 11-48-21',
'VIP 198 2024-12-13 11-48-28',
'VIP 199 2024-12-13 11-48-35',
]
x = await nor_get_reports('10.145.1.1', 'AAAA', '1234', ns)
print(x)
# for n in ns:
# x = parse_report(await ftp_fetch(c, n))
# print(x)
# asyncio.run(main())