On Saturday, August 13, 2016 at 9:14:55 AM UTC-4, Steve Sykes wrote:
>
> Now weewx is running and not crashing, however in the LOOP readings when I
> am running from command line, I don't see the new units from the as3935:
>
> LOOP: 2016-08-13 08:51:07 EDT (1471092667) altimeter: 29.8689377295,
> appTemp: 90.5324650998, barometer: 29.846285074, cloudbase: 3238.21408986,
> dateTime: 1471092667, dewpoint: 70.9722580046, extraTemp1: 83.4125,
> extraTemp2: 83.3, extraTemp3: 82.7375, heatindex: 86.8483964727, humidex:
> 98.6022225192, inDewpoint: None, inTemp: 82.85, lightning: 0.0,
> maxSolarRad: 382.747490845, outHumidity: 68.508869, outTemp: 82.4,
> pressure: 29.1918655641, rain: 0.0, rainRate: 0, usUnits: 1, windchill:
> 82.4, windDir: None, windSpeed: 0.0
>
> The lightning value pertains to the hobbyboards detector. Shouldn’t I also
> see avg_distance and lightning_strikes?
>>
>>
>>>
steve,
you will only see the lightning data in each archive record, not each loop.
this is because the service is bound to weewx.NEW_ARCHIVE_RECORD
version 0.5rc1 is attached. it lets you specify loop binding instead of
archive:
[AS3835]
binding = loop
give it a try and let us know what you get.
m
# $Id: as3935.py 1494 2016-08-12 23:42:27Z mwall $
# Copyright 2015 Matthew Wall
"""
A service for weewx that reads the AS3935 lightning sensor range. This service
will add two fields to each archive record:
lightning_strikes - number of lightning strikes in the pass archive interval
avg_distance - average distance of the lightning strikes
To track these and use them in reports and plots, extend the schema as
described in the weewx customization guide.
The service can also save data to a separate 'lightning' database. To enable
this feature, specify a data_binding in the AS3935 section of weewx.conf.
Configuration:
Rev. 1 Raspberry Pis should leave bus set at 0, while rev. 2 Pis should
set bus equal to 1. The address should be changed to match the address of
the sensor. Common implementations are in README.md.
[AS3935]
address = 3
bus = 1
noise_floor = 0
calibration = 6
indoors = True
pin = 17
data_binding = lightning_binding
[DataBindings]
[[lightning_binding]]
database = lightning_sqlite
[Databases]
[[lightning_sqlite]]
root = %(WEEWX_ROOT)s
database_name = archive/lightning.sdb
driver = weedb.sqlite
[Engine]
[[Services]]
data_services = ..., user.as3935.AS3935
Packet binding:
The service can be bound to LOOP packets or archive records. Default is
archive records. Use the binding parameter to specify, for example:
[AS3935]
binding = loop
Credit:
Based on Phil Fenstermacher's RaspberryPi-AS3935 library and demo.py script.
https://github.com/pcfens/RaspberryPi-AS3935
"""
from RPi_AS3935 import RPi_AS3935
import RPi.GPIO as GPIO
import time
import syslog
import weewx
import weewx.manager
from datetime import datetime
from weewx.wxengine import StdService
from weeutil.weeutil import to_bool
VERSION = "0.5rc1"
if weewx.__version__ < "3.2":
raise weewx.UnsupportedFeature("weewx 3 is required, found %s" %
weewx.__version__)
# uncomment this if you want to sum counts instead of getting counts per period
#weewx.accum.extract_dict['lightning_strikes'] = weewx.accum.Accum.sum_extract
schema = [('dateTime', 'INTEGER NOT NULL PRIMARY KEY'),
('usUnits', 'INTEGER NOT NULL'),
('distance', 'REAL')]
def get_default_binding_dict():
return {'database': 'lightning_sqlite',
'manager': 'weewx.manager.Manager',
'table_name': 'archive',
'schema': 'user.as3935.schema'}
def logmsg(level, msg):
syslog.syslog(level, 'as3935: %s' % msg)
def logdbg(msg):
logmsg(syslog.LOG_DEBUG, msg)
def loginf(msg):
logmsg(syslog.LOG_INFO, msg)
def logerr(msg):
logmsg(syslog.LOG_ERR, msg)
class AS3935(StdService):
def __init__(self, engine, config_dict):
super(AS3935, self).__init__(engine, config_dict)
loginf("service version is %s" % VERSION)
svc_dict = config_dict.get('AS3935', {})
addr = int(svc_dict.get('address', 0x03))
bus = int(svc_dict.get('bus', 1))
indoors = to_bool(svc_dict.get('indoors', True))
noise_floor = int(svc_dict.get('noise_floor', 0))
calib = int(svc_dict.get('calibration', 0x6))
self.pin = int(svc_dict.get('pin', 17))
self.binding = svc_dict.get('data_binding', None)
pkt_binding = svc_dict.get('binding', 'archive')
self.data = []
# if a binding was specified, then use it to save strikes to database
if self.binding is not None:
# configure the lightning database
dbm_dict = weewx.manager.get_manager_dict(
config_dict['DataBindings'], config_dict['Databases'],
self.binding, default_binding_dict=get_default_binding_dict())
with weewx.manager.open_manager(dbm_dict, initialize=True) as dbm:
# ensure schema on disk matches schema in memory
dbcol = dbm.connection.columnsOf(dbm.table_name)
memcol = [x[0] for x in dbm_dict['schema']]
if dbcol != memcol:
raise Exception('as3935: schema mismatch: %s != %s' %
(dbcol, memcol))
# configure the sensor
self.sensor = RPi_AS3935(address=addr, bus=bus)
self.sensor.set_indoors(indoors)
self.sensor.set_noise_floor(noise_floor)
self.sensor.calibrate(tun_cap=calib)
# configure the gpio
GPIO.setmode(GPIO.BCM)
GPIO.setup(self.pin, GPIO.IN)
# add a gpio callback for the lightning strikes
try:
# be sure nothing is registered already...
GPIO.remove_event_detect(self.pin)
except:
pass
# ... then add our handler
GPIO.add_event_detect(self.pin, GPIO.RISING,
callback=self.handle_interrupt)
# on each new record, read then clear data since last record
if pkt_binding.lower() == 'loop':
self.bind(weewx.NEW_LOOP_PACKET, self.new_loop_packet)
else:
self.bind(weewx.NEW_ARCHIVE_RECORD, self.new_archive_record)
def shutDown(self):
GPIO.remove_event_detect(self.pin)
GPIO.cleanup()
def new_loop_packet(self, event):
self.read_data(event.packet)
def new_archive_record(self, event):
self.read_data(event.record)
def read_data(self, pkt):
avg = None
count = len(self.data)
if count:
avg = 0
for x in self.data:
avg += x[1]
avg /= count
# if the record is not metric, convert from kilometers to miles
if 'usUnits' in pkt and pkt['usUnits'] == weewx.US:
avg = weewx.units.convert((avg, 'km', 'group_distance'), 'mile')[0]
# save the count and average
pkt['avg_distance'] = avg
pkt['lightning_strikes'] = count
# clear the count and average
self.data = []
def save_data(self, strike_ts, distance):
if self.binding is None:
return
rec = {'dateTime': strike_ts,
'usUnits': weewx.METRIC,
'distance': distance}
dbm_dict = weewx.manager.get_manager_dict(
self.config_dict['DataBindings'], self.config_dict['Databases'],
self.binding, default_binding_dict=get_default_binding_dict())
with weewx.manager.open_manager(dbm_dict) as dbm:
dbm.addRecord(rec)
def handle_interrupt(self, channel):
try:
time.sleep(0.003)
reason = self.sensor.get_interrupt()
if reason == 0x01:
loginf("noise level too high - adjusting")
self.sensor.raise_noise_floor()
elif reason == 0x04:
loginf("detected disturber - masking")
self.sensor.set_mask_disturber(True)
elif reason == 0x08:
strike_ts = int(time.time())
distance = float(self.sensor.get_distance())
loginf("strike at %s km" % distance)
self.data.append((strike_ts, distance))
self.save_data(strike_ts, distance)
except Exception, e:
logerr("callback failed: %s" % e)