Skip to content

Commit dd8e4da

Browse files
committed
Change timestamp to date_time object
I think this makes this more generally useful for people. You can put anything in the date_time field, even a timestamp if you want, but the default is datetime.now()
1 parent 97957f7 commit dd8e4da

File tree

4 files changed

+48
-41
lines changed

4 files changed

+48
-41
lines changed

README.md

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,56 +9,64 @@ Currently it is just a set of helper classes for taking bytearrays returned by t
99

1010
### Status Packet
1111

12-
The `StatusPacket` class takes a bytearray returned from the Status GATT characteristic and an optional timestamp and creates a data structure with fields corresponding to the different status flags:
12+
The `StatusPacket` class takes a bytearray returned from the Status GATT characteristic and an optional datetime and creates a data structure with fields corresponding to the different status flags:
1313

1414
```python
1515
from atmotube import StatusPacket
16+
from datetime import datetime
1617

18+
example_date = datetime(2024, 1, 1, 12, 0, 0)
1719
example_status = bytearray(b'Ad')
18-
packet = StatusPacket(example_status)
20+
packet = StatusPacket(example_status, date_time=example_date)
1921

2022
print(packet)
21-
# StatusPacket(pm_sensor_status=True, error_flag=False, bonding_flag=False, charging=False, charging_timer=False, pre_heating=True, battery_level=100%)
23+
# StatusPacket(date_time=2024-01-01 12:00:00, pm_sensor_status=True, error_flag=False, bonding_flag=False, charging=False, charging_timer=False, pre_heating=True, battery_level=100%)
2224
```
2325

2426
### SPS30 Packet
2527

26-
The `SPS30Packet` takes a bytearray returned from the SPS30 GATT characteristic with an optional timestamp and creates a data structure with fields corresponding to the PM measurements in ug/m^3
28+
The `SPS30Packet` takes a bytearray returned from the SPS30 GATT characteristic with an optional datetime and creates a data structure with fields corresponding to the PM measurements in ug/m^3
2729

2830
```python
2931
from atmotube import SPS30Packet
32+
from datetime import datetime
3033

34+
example_date = datetime(2024, 1, 1, 12, 0, 0)
3135
example_sps30 = bytearray(b'd\x00\x00\xb9\x00\x00J\x01\x00o\x00\x00')
32-
packet = SPS30Packet(example_sps30)
36+
packet = SPS30Packet(example_sps30, date_time=example_date)
3337

3438
print(packet)
35-
# SPS30Packet(pm1=1.0µg/m³, pm2_5=1.85µg/m³, pm10=3.3µg/m³, pm4=1.11µg/m³)
39+
# SPS30Packet(date_time=2024-01-01 12:00:00, pm1=1.0µg/m³, pm2_5=1.85µg/m³, pm10=3.3µg/m³, pm4=1.11µg/m³)
3640
```
3741

3842
### BME280 Packet
3943

40-
The `BME280Packet` takes a bytearray returned from the BME280 GATT characteristic with an optional timestamp and creates a datastructure with fields corresponding the temperature, pressure, and humidity.
44+
The `BME280Packet` takes a bytearray returned from the BME280 GATT characteristic with an optional datetime and creates a datastructure with fields corresponding the temperature, pressure, and humidity.
4145

4246
```python
4347
from atmotube import BME280Packet
48+
from datetime import datetime
4449

50+
example_date = datetime(2024, 1, 1, 12, 0, 0)
4551
example_bme280 = bytearray(b'\x0e\x17\x8ao\x01\x00\x1a\t')
46-
packet = BME280Packet(example_bme280)
52+
packet = BME280Packet(example_bme280, date_time=example_date)
4753

4854
print(packet)
49-
# BME280Packet(humidity=14%, temperature=23.3°C, pressure=940.9mbar)
55+
# BME280Packet(date_time=2024-01-01 12:00:00, humidity=14%, temperature=23.3°C, pressure=940.9mbar)
5056
```
5157

5258
### SGPC3 Packet
5359

54-
The `SGPC3Packet` takes a bytearray returned from the SGPC3 GATT characteristic with an optional timestamp and creates a datastructure with a single field for the VOC.
60+
The `SGPC3Packet` takes a bytearray returned from the SGPC3 GATT characteristic with an optional datetime and creates a datastructure with a single field for the VOC.
5561

5662
```python
5763
from atmotube import SGPC3Packet
64+
from datetime import datetime
5865

66+
example_date = datetime(2024, 1, 1, 12, 0, 0)
5967
example_sgpc3 = bytearray(b'\x02\x00\x00\x00')
60-
packet = SGPC3Packet(example_sgpc3)
68+
packet = SGPC3Packet(example_sgpc3, date_time=example_date)
6169

6270
print(packet)
63-
# SGPC3Packet(tvoc=0.002ppb)
71+
# SGPC3Packet(date_time=2024-01-01 12:00:00, tvoc=0.002ppb)
6472
```

atmotube/packets.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from ctypes import LittleEndianStructure, c_ubyte, c_byte, c_short, c_int
2-
import time
2+
from datetime import datetime
33

44

55
class InvalidByteData(Exception):
@@ -9,16 +9,16 @@ class InvalidByteData(Exception):
99
class AtmoTubePacket(LittleEndianStructure):
1010
_byte_size_ = 0 # To be defined in subclasses
1111

12-
def __new__(cls, data, ts=None):
12+
def __new__(cls, data, date_time=None):
1313
if len(data) != cls._byte_size_:
1414
raise InvalidByteData(f"Expected {cls._byte_size_} bytes, "
1515
f"got {len(data)} bytes")
1616
return cls.from_buffer_copy(data)
1717

18-
def __init__(self, data, ts=None):
19-
if ts is None:
20-
ts = time.time()
21-
self.timestamp = ts
18+
def __init__(self, data, date_time=None):
19+
if date_time is None:
20+
date_time = datetime.now()
21+
self.date_time = date_time
2222
self._process_bytes()
2323

2424
def __repr__(self):
@@ -53,7 +53,7 @@ def _process_bytes(self):
5353
self.battery_level = self._battery
5454

5555
def __str__(self):
56-
return (f"StatusPacket(timestamp={time.ctime(self.timestamp)}, "
56+
return (f"StatusPacket(date_time={str(self.date_time)}, "
5757
f"pm_sensor_status={self.pm_sensor_status}, "
5858
f"error_flag={self.error_flag}, "
5959
f"bonding_flag={self.bonding_flag}, "
@@ -86,7 +86,7 @@ def _process_bytes(self):
8686
self.pm4 = self.pm_from_bytes(self._pm4)
8787

8888
def __str__(self):
89-
return (f"SPS30Packet(timestamp={time.ctime(self.timestamp)}, "
89+
return (f"SPS30Packet(date_time={str(self.date_time)}, "
9090
f"pm1={self.pm1}µg/m³, pm2_5={self.pm2_5}µg/m³, "
9191
f"pm10={self.pm10}µg/m³, pm4={self.pm4}µg/m³)")
9292

@@ -109,7 +109,7 @@ def _process_bytes(self):
109109
self.pressure = self._P / 100.0 if self._P > 0 else None
110110

111111
def __str__(self):
112-
return (f"BME280Packet(timestamp={time.ctime(self.timestamp)}, "
112+
return (f"BME280Packet(date_time={str(self.date_time)}, "
113113
f"humidity={self.humidity}%, "
114114
f"temperature={self.temperature}°C, "
115115
f"pressure={self.pressure}mbar)")
@@ -128,5 +128,5 @@ def _process_bytes(self):
128128
self.tvoc = self._tvoc/1000.0 if self._tvoc > 0 else None
129129

130130
def __str__(self):
131-
return (f"SGPC3Packet(timestamp={time.ctime(self.timestamp)}, "
131+
return (f"SGPC3Packet(date_time={str(self.date_time)}, "
132132
f"tvoc={self.tvoc}ppb)")

examples/data_logging_example.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from atmotube import BME280Packet, SGPC3Packet
1111
import asyncio
1212
import logging
13-
import time
1413

1514
ATMOTUBE = "C2:2B:42:15:30:89" # the mac address of my Atmotube
1615

@@ -48,23 +47,23 @@ async def sgp30_cb(char, data):
4847
def log_packet(packet):
4948
match packet:
5049
case StatusPacket():
51-
logging.info(f"{time.ctime(packet.timestamp)} - Status Packet - "
50+
logging.info(f"{str(packet.date_time)} - Status Packet - "
5251
f"Battery: {packet.battery_level}%, "
5352
f"Charging: {packet.charging}, "
5453
f"Error: {packet.error_flag}")
5554
case SPS30Packet():
56-
logging.info(f"{time.ctime(packet.timestamp)} - SPS30 Packet - "
55+
logging.info(f"{str(packet.date_time)} - SPS30 Packet - "
5756
f"PM1: {packet.pm1} µg/m³, "
5857
f"PM2.5: {packet.pm2_5} µg/m³, "
5958
f"PM4: {packet.pm4} µg/m³, "
6059
f"PM10: {packet.pm10} µg/m³")
6160
case BME280Packet():
62-
logging.info(f"{time.ctime(packet.timestamp)} - BME280 Packet - "
61+
logging.info(f"{str(packet.date_time)} - BME280 Packet - "
6362
f"Humidity: {packet.humidity}%, "
6463
f"Temperature: {packet.temperature}°C, "
6564
f"Pressure: {packet.pressure} mbar")
6665
case SGPC3Packet():
67-
logging.info(f"{time.ctime(packet.timestamp)} - SGPC3 Packet - "
66+
logging.info(f"{str(packet.date_time)} - SGPC3 Packet - "
6867
f"TVOC: {packet.tvoc} ppb")
6968
case _:
7069
logging.info("Unknown packet type")

tests/test_packets.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
from atmotube import InvalidByteData
22
from atmotube import StatusPacket, SPS30Packet, BME280Packet, SGPC3Packet
3+
from datetime import datetime
34

45
import pytest
5-
import time
66

77
# Status Packet tests
8-
timestamp = 1766865019.792235
8+
datetime_obj = datetime(2024, 1, 1, 12, 0, 0)
99
status_test_byte = bytearray(b'Ad')
1010
status_test_invalid_byte = bytearray(b'A')
11-
status_packet_str = (f"StatusPacket(timestamp={time.ctime(timestamp)}, "
11+
status_packet_str = (f"StatusPacket(date_time={str(datetime_obj)}, "
1212
f"pm_sensor_status=True, "
1313
f"error_flag=False, bonding_flag=False, "
1414
f"charging=False, charging_timer=False, "
1515
f"pre_heating=True, battery_level=100%)")
1616

1717

1818
def test_status_packet():
19-
packet = StatusPacket(status_test_byte, ts=timestamp)
19+
packet = StatusPacket(status_test_byte, date_time=datetime_obj)
2020
assert packet.pm_sensor_status is True
2121
assert packet.error_flag is False
2222
assert packet.bonding_flag is False
@@ -27,59 +27,59 @@ def test_status_packet():
2727
assert str(packet) == status_packet_str
2828
assert repr(packet) == status_packet_str
2929
with pytest.raises(InvalidByteData):
30-
StatusPacket(status_test_invalid_byte, ts=timestamp)
30+
StatusPacket(status_test_invalid_byte, date_time=datetime_obj)
3131

3232

3333
# SPS30 Packet tests
3434
sps30_test_byte = bytearray(b'd\x00\x00\xb9\x00\x00J\x01\x00o\x00\x00')
3535
sps30_test_invalid_byte = bytearray(b'd\x00\x00\xb9\x00\x00J\x01')
36-
sps30_test_str = (f"SPS30Packet(timestamp={time.ctime(timestamp)}, "
36+
sps30_test_str = (f"SPS30Packet(date_time={str(datetime_obj)}, "
3737
f"pm1=1.0µg/m³, pm2_5=1.85µg/m³, "
3838
f"pm10=3.3µg/m³, pm4=1.11µg/m³)")
3939

4040

4141
def test_sps30_packet():
42-
packet = SPS30Packet(sps30_test_byte, ts=timestamp)
42+
packet = SPS30Packet(sps30_test_byte, date_time=datetime_obj)
4343
assert packet.pm1 == 1.0
4444
assert packet.pm2_5 == 1.85
4545
assert packet.pm10 == 3.3
4646
assert packet.pm4 == 1.11
4747
assert str(packet) == sps30_test_str
4848
assert repr(packet) == sps30_test_str
4949
with pytest.raises(InvalidByteData):
50-
SPS30Packet(sps30_test_invalid_byte, ts=timestamp)
50+
SPS30Packet(sps30_test_invalid_byte, date_time=datetime_obj)
5151

5252

5353
# BME280 Packet tests
5454
bme280_test_byte = bytearray(b'\x0e\x17\x8ao\x01\x00\x1a\t')
5555
bme280_test_invalid_byte = bytearray(b'\x0e\x17\x8ao\x01')
56-
bme280_test_str = (f"BME280Packet(timestamp={time.ctime(timestamp)}, "
56+
bme280_test_str = (f"BME280Packet(date_time={str(datetime_obj)}, "
5757
f"humidity=14%, temperature=23.3°C, "
5858
f"pressure=940.9mbar)")
5959

6060

6161
def test_bme280_packet():
62-
packet = BME280Packet(bme280_test_byte, ts=timestamp)
62+
packet = BME280Packet(bme280_test_byte, date_time=datetime_obj)
6363
assert packet.humidity == 14
6464
assert packet.temperature == 23.3
6565
assert packet.pressure == 940.9
6666
assert str(packet) == bme280_test_str
6767
assert repr(packet) == bme280_test_str
6868
with pytest.raises(InvalidByteData):
69-
BME280Packet(bme280_test_invalid_byte, ts=timestamp)
69+
BME280Packet(bme280_test_invalid_byte, date_time=datetime_obj)
7070

7171

7272
# SGPC3 Packet tests
7373
sgpc3_test_byte = bytearray(b'\x02\x00\x00\x00')
7474
sgpc3_test_invalid_byte = bytearray(b'\x02\x00\x00')
75-
sgpc3_test_str = (f"SGPC3Packet(timestamp={time.ctime(timestamp)}, "
75+
sgpc3_test_str = (f"SGPC3Packet(date_time={str(datetime_obj)}, "
7676
f"tvoc=0.002ppb)")
7777

7878

7979
def test_sgpc3_packet():
80-
packet = SGPC3Packet(sgpc3_test_byte, ts=timestamp)
80+
packet = SGPC3Packet(sgpc3_test_byte, date_time=datetime_obj)
8181
assert packet.tvoc == 0.002
8282
assert str(packet) == sgpc3_test_str
8383
assert repr(packet) == sgpc3_test_str
8484
with pytest.raises(InvalidByteData):
85-
SGPC3Packet(sgpc3_test_invalid_byte, ts=timestamp)
85+
SGPC3Packet(sgpc3_test_invalid_byte, date_time=datetime_obj)

0 commit comments

Comments
 (0)