Way more complex than I think is needed. I would see you using the SDR
driver as the your driver and nothing else. The example cited in the
Customisation Guide does augment archive records rather than loop packets,
in your case I would expect you are better served by augmenting loop
packets. You don't necessarily need to augment every loop packet (if your
loop packets are coming in every 7 seconds from SDR) but you need to make
sure you get a good few in each archive period. You should have no need to
deal with queues or accumulators in your service, the queue is a hangover
of the threaded SDR driver and the WeeWX engine should handle everything to
do with accumulators. At then end of the day you want to do two things (1)
feed WeeWX with a loop packet stream - the SDR driver does that and (2)
augment loop packets with Arduino data - your service does that. If you do
these two things WeeWX will take care of generating archive records,
reports etc.
For the Arduino, can't you just read the Arduino data direct from the
serial port and decode/parse/process it in your service? (there seems to be
plenty of examples around the traps on this).
The sort of service I had in mind is something like (untested of course):
import weewx
import weewx.units
class ArduinoService(weewx.engine.StdService):
"""Data service to augment loop packets with data from an Arduino.
We will augment loop packets with obs obtained from the Arduino. The
WeeWX
engine will take care of accumulating this data and generating archive
records.
"""
def __init__(self, engine, config_dict):
# initialisie my parent class
super(ArduinoService, self).__init__(engine, config_dict)
# include whatever initialisation you need to speak to the Arduino
< some python code to initialise any properties etc>
# we will augment loop packets so bind ourself to any new loop
packet
# events
self.bind(weewx.NEW_LOOP_PACKET, self.new_loop_packet)
def new_loop_packet(self, event):
"""Augment a loop packet with data obtained from the Arduino."""
# obtain a dict of data from the Arduino
_ard_data_dict = self.get_arduino_data()
# do we have any data
if _ard_data_dict is not None:
# convert the Arduino data to the same unit system as used in
the
# loop packet, first obtain a suitable Converter
converter =
weewx.units.StdUnitConverters[event.packet['usUnits']]
# now convert the Arduino data to the same unit system as used
in
# the loop packet
_conv_data = converter.convertDict(_ard_data_dict)
# and finally update the loop packet with our converted data
event.packet.update(_conv_data)
def get_arduino_data():
"""Get a data dict from the Arduino.
Obtain any data from the Arduino, parse the data and return as a
dict
using a known unit system. If no data could be obtained return None.
"""
# some code to obtain the data from the Arduino, this code needs to
be
# carefully constructed to not block
< python code to read data from the Arduino>
if <we have Arduino data>:
# create an empty dict with a pre-populated field usUnits to
hold
# our parsed Arduino data. The usUnits value is arbitrary, but
must
# be one of weewx.US (1), weewx.METRIC (16) or weewx.METRICWX
(17).
# Choose a conventient value, eg if the Arduino provides data
in
# metric use weewx.METRIC (16), if US customary use weewx.US,
if a
# mix of both then pick one and we will need to do some manual
# conversion for the odd fields. In this case we will use
# weewx.METRIC
_data_dict = {'usunits': weewx.METRIC}
# populate the dict, assuming here the Arduino is providing
WeeWX
# fields inTemp, inHumidity and barometer (could be 'pressure'
not
# 'barometer')
_data_dict['inTemp'] = <some code to provide inside temperature
in degree C>
_data_dict['inHumidity'] = <some code to provide inside
humidity in percent>
_data_dict['barometer'] = <some code to provide barometer in
hPa>
# we have our data dict, now return it
return _data_dict
# we could not get any data from the Arduino so return None
return None
This is fairly bare bones and you might want to put in a few pieces of code
to provide log output when debug = 1 (or 2 or 3) but hopefully you get the
idea
Gary
On Thursday, 27 April 2023 at 15:08:42 UTC+10 [email protected] wrote:
> here is my service. In this version I took your advice and decided to use
> the weewx-sdr driver completely unmodified and put all my stuff in a
> service. Sorry the weewx-sdr driver (the original, not my version) reads
> its input from AsyncReader (not my modification). That uses a thread.
> That's what I was referring to. But since I already had my (slightly
> modified) version of AsyncReader from before I spoke to you, I reused it in
> the service (see the attachment). It has a queue. It stores lines of
> input from the arduino over usb and discards any which are not json. This
> is completely separate from the weewx-sdr and its AsyncReader. Plus this
> AsyncReader can also be set up as a writer which enables me to have the
> option of a simple time server on the raspberry pi to set the RTC on the
> arduino if needed.
>
> Anyway I could always get rid of the AsyncReader and just use
> serial.readline().
>
> Perhaps the example in the weewx customization guide is for a one-shot
> read of the indoors sensors. Instead I made it loop over the lines of
> input in the queue and use an accumulator to average them.
>
> The callback for NEW_ARCHIVE_RECORD for my service would (I think) be
> called before StdArchive.new_archive_record(). My service only has access
> to the event and event.record. Does it also have access to
> StdArchive.old_accumulator ?
> In StdArchive.new_archive_record(event) it gets the event which was
> modified by my service so the record includes my data.
>
> *So my question is* what about old_accumulator in
> StdArchive.new_archive_record() ? Is it strictly optional ? That
> accumulator only has the outside data not the data added by my
> new_archive_record() callback.
> Of course my data is already averaged.
> In StdArchive.new_archive_record() the event.record has more observation
> types than the old_accumulator. Does this pose a problem ?
>
> what do you mean by augmenting? does this involve choosing
> self.record_generation = hardware ?
> On Wednesday, April 26, 2023 at 6:12:50 PM UTC-7 gjr80 wrote:
>
>> Yes, that section covers it fairly well. The two main things to watch are
>> not delaying the main WeeWX engine loop and ensuring the data you add to
>> the loop packet follows the unit system used in the loop packet. Delaying
>> the main loop is often associated with accessing data via the internet or
>> some other network. A common approach is to develop the data service
>> without using its own thread, this makes debugging much easier. If delay is
>> an issue you can move the service to its own thread later. Unit consistency
>> is achieved by checking the usUnits field in the loop packet and then
>> converting your service' data to the correct units. This is important for
>> obs whose units that vary across unit systems (eg temperature) but not an
>> issue if the same unit is used across all unit systems (eg wind direction).
>> A robust, well written data service will not assume the loop packet always
>> uses the same unit system.
>>
>> Gary
>>
>> On Thursday, 27 April 2023 at 01:24:52 UTC+10 [email protected] wrote:
>>
>>> Thank you I expect you are referring to the Customization guide
>>> "Customizing the WeeWX service engine; Adding a second data source"; I will
>>> try doing it that way; Thanks again;
>>>
>>> On Tuesday, April 25, 2023 at 10:16:18 PM UTC-7 gjr80 wrote:
>>>
>>>> I'm not sure if you are providing a running commentary or seeking help.
>>>> If the latter then I have no idea where to start. Personally, I think your
>>>> architecture is way too complex; you appear to be running a highly
>>>> modified
>>>> driver that seeks to amalgamate data from two sources. I imagine you will
>>>> strike all sorts of corner cases depending on what arrives when. I would
>>>> also question the utility of reading indoor obs every seven seconds, seems
>>>> way too frequent to me. All told I doubt you are going to find too many
>>>> folks here to help.
>>>>
>>>> Why not run a standard sdr driver to feed WeeWX with loop packets from
>>>> the Atlas with a simple, non-threaded data service bound to the new loop
>>>> packet arrival to read the 'indoor data' (I assume this is pressure,
>>>> temperature and humidity) and augment the loop packet. Far more modular
>>>> and
>>>> easier to test/develop (and get help), you will be running a standard sdr
>>>> driver, and since you are already getting your hands dirty modifying the
>>>> sdr driver, writing a small data service to handle the Arduino input
>>>> should
>>>> be a walk in the park. If the Arduino is serially connected to the RPi you
>>>> should not have great latency in accessing data, so a suitably short
>>>> timeout on the serial reads should provide you with you indoor data
>>>> without
>>>> blocking the main WeeWX thread. Once proved, the serial read could be
>>>> moved
>>>> to a thread if you really had the need.
>>>>
>>>> Gary
>>>>
>>>
--
You received this message because you are subscribed to the Google Groups
"weewx-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/weewx-user/edf23b07-f378-449d-a5df-c7ebea50a512n%40googlegroups.com.