Package¶
You can build your own tooling around vpf-730 extending its functionality.
The VPF730 class¶
Getting Started - a simple example¶
In this example we provide more custom, non standard options to the vpf_730.VPF730()
class when initializing.
We also disable the poll-mode when calling vpf_730.VPF730.measure()
, and save the result to a csv file.
import time
from vpf_730 import VPF730
vpf730 = VPF730(
port='/dev/ttyS1',
baudrate=9600,
timeout=10,
write_timeout=20,
)
for _ in range(2):
measurement = vpf730.measure(polled_mode=False)
print(f'Current precipitation type: {measurement.precipitation_type_msg_readable}')
# save to a csv file
measurement.to_csv(fname='vpf_730_measurements.csv')
print('=' * 79)
time.sleep(2)
Output to the console
Current precipitation type: No precipitation
===============================================================================
Current precipitation type: No precipitation
===============================================================================
csv-file
timestamp,sensor_id,last_measurement_period,time_since_report,optical_range,precipitation_type_msg,obstruction_to_vision,receiver_bg_illumination,water_in_precip,temp,nr_precip_particles,transmission_eq,exco_less_precip_particle,backscatter_exco,self_test,total_exco
1658758977,1,60,0,1.19,NP,HZ,0.06,0.0,20.5,0,2.51,2.51,11.1,OOO,2.51
1658757779,1,60,0,1.19,NP,HZ,0.06,0.0,20.5,0,2.51,2.51,11.1,OOO,2.51
Adding additional functionality¶
We can inherit from vpf_730.VPF730()
and add additional methods e.g. in this case for synchronizing the clock of the VPF-730 sensor with the server’s clock.
from datetime import datetime
from datetime import timezone
from vpf_730 import VPF730
class VPF730_extended(VPF730):
def sync_clock(self, custom_time: datetime | None = None) -> None:
"""Synchronize the clock of the VPF-730 with the computer's clock.
:param custom_time: if specified, the sensor's clock is set to this
time, otherwise the current time in UTC is chosen.
"""
if custom_time is None:
now = datetime.now(timezone.utc)
else:
now = custom_time
with self.open_ser():
self._ser.write(f'%SD{now:%w%d%m%y}\r\n'.encode())
self._ser.write(f'%ST{now:%H%M%S}\r\n'.encode())
We can also utilize the vpf_730.VPF730.send_command()
method for using other commands.
from vpf_730 import VPF730
class VPF730_extended(VPF730):
def self_test(self) -> str:
"""Execute a self test of the sensor by sending the R? command
:returns: A message formatted like this (more in the manual page 60):
100,2.509,24.1,12.3,5.01,12.5,00.00,00.00,100,105,107,00,00,00,+021.0,4063
"""
with self.open_ser():
self_test_msg = self.send_command('R?')
return self_test_msg.decode()
The Sender class¶
The vpf_730.Sender()
class implements sending data to a remote sender via a http request.
One can subclass vpf_730.Sender()
for e.g. changing the implementation details of the
endpoints.
One example would be using a different endpoint for the get_endpoint
i.e.
utilizing a generic data endpoint to fetch the latest date.
We call this api: https://api.example.com/data
providing the following url-parameters:
param =
optical_range
scale =
max
days =
1
resulting in this url: https://api.example.com/data?param=optical_range&scale=max&days=1
We still provide an Authorization
header using the API-key as defined in vpf_730.SenderConfig()
.
The response looks like this and we can parse it to extract the timestamps and get the maximum of all timestamps to finally return the latest date:
{
"data": [
{
"date": 1658758977,
"optical_range": 1.19
},
{
"date": 1658757779,
"optical_range": 1.19
}
]
}
An implementation could look like this:
import json
import urllib.parse
import urllib.request
from vpf_730 import Sender
from vpf_730 import SenderConfig
class CustomSender(Sender):
def get_remote_timestamp(self) -> int:
url_params = urllib.parse.urlencode({
'param': 'optical_range',
'scale': 'max',
'days': 1,
})
url = f'{self.cfg.get_endpoint}?{url_params}'
status_req = urllib.request.Request(
url=url,
headers={
'Authorization': self.cfg.api_key,
'Content-type': 'application/json',
},
)
status_resp = urllib.request.urlopen(status_req)
status_resp_str = status_resp.read().decode()
data = json.loads(status_resp_str)['data']
latest_date = max([i['date'] for i in data])
return latest_date
sender_cfg = SenderConfig(
local_db='local.db',
send_interval=1,
get_endpoint='https://api.example.com/data',
post_endpoint='https://api.example.com/vpf-730/insert',
max_req_len=256,
api_key='deadbeef',
)
sender = CustomSender(sender_cfg)
sender.run()