2024-05-31 17:45:44 +03:00
|
|
|
import json
|
2024-05-31 16:37:42 +03:00
|
|
|
from urllib.parse import quote
|
|
|
|
|
2024-05-31 14:58:46 +03:00
|
|
|
from dataclasses import dataclass
|
2024-05-31 17:45:44 +03:00
|
|
|
from typing import Collection, Any
|
2024-05-31 16:37:42 +03:00
|
|
|
|
|
|
|
|
|
|
|
type Numeric = int | float
|
2024-05-31 14:58:46 +03:00
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class SensorData:
|
|
|
|
mac: str
|
2024-05-31 16:37:42 +03:00
|
|
|
value: Numeric
|
|
|
|
# actually `time` is either decimal int,
|
|
|
|
# hex int or <date>T<time>+/-<timezone>
|
2024-05-31 14:58:46 +03:00
|
|
|
time: int | None = None
|
|
|
|
name: str | None = None
|
2024-05-31 15:09:48 +03:00
|
|
|
|
|
|
|
|
2024-05-31 16:37:42 +03:00
|
|
|
@dataclass
|
|
|
|
class GeoPosition:
|
|
|
|
lat: Numeric
|
|
|
|
lon: Numeric
|
|
|
|
alt: Numeric
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class Device:
|
|
|
|
mac: str
|
|
|
|
name: str | None = None
|
|
|
|
owner: str | None = None
|
|
|
|
geopos: GeoPosition | None = None
|
|
|
|
sensors: Collection[SensorData] = ()
|
2024-05-31 15:09:48 +03:00
|
|
|
|
2024-05-31 16:37:42 +03:00
|
|
|
def nm_req_data(self) -> str:
|
|
|
|
'''Generate a NarodMon format (#mac#value) request body'''
|
2024-05-31 15:09:48 +03:00
|
|
|
|
2024-05-31 16:37:42 +03:00
|
|
|
res = '#' + self.mac
|
|
|
|
if self.name is not None:
|
|
|
|
res += '#' + self.name
|
2024-05-31 15:09:48 +03:00
|
|
|
res += '\n'
|
|
|
|
|
2024-05-31 16:37:42 +03:00
|
|
|
if self.owner is not None:
|
|
|
|
res += '#OWNER#' + self.owner + '\n'
|
|
|
|
|
|
|
|
for s in self.sensors:
|
|
|
|
res += f'#{s.mac}#{s.value}'
|
|
|
|
if s.time is not None:
|
|
|
|
res += f'#{s.time}'
|
|
|
|
if s.name is not None:
|
|
|
|
res += '#' + s.name
|
|
|
|
res += '\n'
|
|
|
|
|
|
|
|
if self.geopos is not None:
|
|
|
|
res += (
|
|
|
|
f'#LAT#{self.geopos.lat}\n'
|
|
|
|
f'#LON#{self.geopos.lon}\n'
|
|
|
|
f'#ALT#{self.geopos.alt}\n'
|
|
|
|
)
|
|
|
|
|
|
|
|
res += '##'
|
|
|
|
|
|
|
|
return res
|
|
|
|
|
|
|
|
def http_req_data(self) -> str:
|
|
|
|
'''Generate an x-www-form-urlencoded format request body'''
|
|
|
|
|
|
|
|
res = 'ID=' + self.mac
|
|
|
|
# TODO: i didn't get how to pass device name in an HTTP request
|
|
|
|
# because narodmon docs are written incredibly well /sarcasm
|
|
|
|
|
|
|
|
for s in self.sensors:
|
|
|
|
res += f'&{s.mac}={s.value}'
|
|
|
|
if s.time is not None:
|
|
|
|
res += f'&time={s.time}'
|
|
|
|
if s.name is not None:
|
|
|
|
res += f'&name={quote(s.name)}'
|
|
|
|
|
|
|
|
if self.owner is not None:
|
|
|
|
res += '&owner=' + quote(self.owner)
|
|
|
|
|
|
|
|
if self.geopos is not None:
|
|
|
|
res += (
|
|
|
|
f'&lat={self.geopos.lat}'
|
|
|
|
f'&lon={self.geopos.lon}'
|
|
|
|
f'&alt={self.geopos.alt}'
|
|
|
|
)
|
|
|
|
|
|
|
|
return res
|
2024-05-31 15:28:21 +03:00
|
|
|
|
2024-05-31 16:37:42 +03:00
|
|
|
def json_req_data(self) -> str:
|
2024-05-31 17:45:44 +03:00
|
|
|
'''Generate a JSON format request body'''
|
|
|
|
|
|
|
|
obj = {
|
|
|
|
'devices': [{
|
|
|
|
'mac': self.mac,
|
|
|
|
'sensors': [],
|
|
|
|
}]
|
|
|
|
}
|
|
|
|
|
|
|
|
dev = obj['devices'][0]
|
|
|
|
if self.name is not None:
|
|
|
|
dev['name'] = self.name
|
|
|
|
if self.owner is not None:
|
|
|
|
dev['owner'] = self.owner
|
|
|
|
if self.geopos is not None:
|
|
|
|
dev['lat'] = self.geopos.lat
|
|
|
|
dev['lon'] = self.geopos.lon
|
|
|
|
dev['alt'] = self.geopos.alt
|
|
|
|
|
|
|
|
sl: list[dict[str, Any]] = dev['sensors']
|
|
|
|
for s in self.sensors:
|
|
|
|
sobj = {
|
|
|
|
'id': s.mac,
|
|
|
|
'value': s.value,
|
|
|
|
}
|
|
|
|
if s.time is not None:
|
|
|
|
sobj['time'] = s.time
|
|
|
|
if s.name is not None:
|
|
|
|
sobj['name'] = s.name
|
|
|
|
sl.append(sobj)
|
|
|
|
|
|
|
|
return json.dumps(obj)
|