Skip to content

Commit 7139033

Browse files
committed
eliminate experimental directory, move examples directory. addresses issue weewx#183
1 parent 2d6d186 commit 7139033

9 files changed

+156
-141
lines changed

docs/changes.txt

+6-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ Fixed reference to index.html.tmpl in the xstats example.
3535
Changed algorithm for calculating ET to something more appropriate for
3636
hourly values (former algorithm assumed daily values). Fixes issue #160.
3737

38-
Fixed bug that was introduced in v3.6.0, which prevented wee_reports from working
39-
for anything other than the current time.
38+
Fixed bug that was introduced in v3.6.0, which prevented wee_reports from
39+
working for anything other than the current time.
4040

4141
Documented the experimental anti-alias feature, which has been in weewx
4242
since v3.1.0. Fixes issue #6.
@@ -45,6 +45,10 @@ Can now do SummaryByDay (as well as SummaryByMonth and SummaryByYear).
4545
NB: This can generate *lots* of files --- one for every day in your database!
4646
Leaving this undocumented for now. Fixes issue #185.
4747

48+
Moved examples out of bin directory. Eliminated experimental directory.
49+
Reinforce the use of user directory, eliminate use of examples directory.
50+
Renamed xsearch.py to stats.py.
51+
4852

4953
3.6.2 11/08/2016
5054

docs/customizing.htm

+36-34
Original file line numberDiff line numberDiff line change
@@ -2229,15 +2229,15 @@ <h3 id="extending_the_list">Extending the list</h3>
22292229
</li>
22302230
</ul>
22312231
<p>This example is included in the distribution as
2232-
<span class="code">examples/xsearch.py</span>: </p>
2232+
<span class="code">examples/stats.py</span>: </p>
22332233
<pre class="tty">import datetime
22342234
import time
22352235

22362236
from weewx.cheetahgenerator import SearchList
22372237
from weewx.tags import TimespanBinder
22382238
from weeutil.weeutil import TimeSpan
22392239

2240-
class MyXSearch(SearchList): # 1
2240+
class MyStats(SearchList): # 1
22412241
"""My search list extension"""
22422242

22432243
def __init__(self, generator): # 2
@@ -2287,7 +2287,7 @@ <h3 id="extending_the_list">Extending the list</h3>
22872287

22882288
<p>Going through the example, line by line: </p>
22892289
<ol>
2290-
<li>Create a new class called <span class="code">MyXSearch</span>,
2290+
<li>Create a new class called <span class="code">MyStats</span>,
22912291
which will inherit from class <span class="code">SearchList</span>. All
22922292
search list extensions inherit from this class.
22932293
</li>
@@ -2383,7 +2383,7 @@ <h3 id="extending_the_list">Extending the list</h3>
23832383

23842384
# Possible encodings are 'html_entities', 'utf8', or 'strict_ascii'
23852385
encoding = html_entities
2386-
<span class="highlight">search_list_extensions = examples.xsearch.MyXSearch</span>
2386+
<span class="highlight">search_list_extensions = user.stats.MyStats</span>
23872387

23882388
[[SummaryByMonth]]
23892389
...
@@ -3683,7 +3683,7 @@ <h3>File generation options</h3>
36833683
<p>This defines one or more search list objects that will be appended to
36843684
the <span class="config_option">search_list</span>. For example, the
36853685
following adds alltime and forecast variables to the search list.</p>
3686-
<pre class="tty">search_list_extensions = examples.xsearch.MyXSearch, user.forecast.ForecastVariables</pre>
3686+
<pre class="tty">search_list_extensions = user.stats.MyStats, user.forecast.ForecastVariables</pre>
36873687
<p class="config_option">encoding </p>
36883688

36893689
<p>This option controls which encoding is to be used for the generated
@@ -4521,15 +4521,15 @@ <h2 id="Adding_a_service">Adding a service</h2>
45214521

45224522
# Inherit from the base class StdService:
45234523
class MyAlarm(StdService):
4524-
"""Custom service that sounds an alarm if an arbitrary expression evaluates true"""
4525-
4524+
"""Service that sends email if an arbitrary expression evaluates true"""
4525+
45264526
def __init__(self, engine, config_dict):
45274527
# Pass the initialization information on to my superclass:
45284528
super(MyAlarm, self).__init__(engine, config_dict)
4529-
4529+
45304530
# This will hold the time when the last alarm message went out:
45314531
self.last_msg_ts = 0
4532-
4532+
45334533
try:
45344534
# Dig the needed options out of the configuration dictionary.
45354535
# If a critical option is missing, an exception will be raised and
@@ -4540,27 +4540,26 @@ <h2 id="Adding_a_service">Adding a service</h2>
45404540
self.smtp_user = config_dict['Alarm'].get('smtp_user')
45414541
self.smtp_password = config_dict['Alarm'].get('smtp_password')
45424542
self.SUBJECT = config_dict['Alarm'].get('subject', "Alarm message from weewx")
4543-
self.FROM = config_dict['Alarm'].get('from', 'alarm@weewx.com')
4543+
self.FROM = config_dict['Alarm'].get('from', 'alarm@example.com')
45444544
self.TO = option_as_list(config_dict['Alarm']['mailto'])
45454545
syslog.syslog(syslog.LOG_INFO, "alarm: Alarm set for expression: '%s'" % self.expression)
4546-
4546+
45474547
# If we got this far, it's ok to start intercepting events:
45484548
self.bind(weewx.NEW_ARCHIVE_RECORD, self.newArchiveRecord) # NOTE 1
4549-
45504549
except KeyError, e:
4551-
syslog.syslog(syslog.LOG_INFO, "alarm: No alarm set. %s" % e)
4552-
4550+
syslog.syslog(syslog.LOG_INFO, "alarm: No alarm set. Missing parameter: %s" % e)
4551+
45534552
def newArchiveRecord(self, event):
45544553
"""Gets called on a new archive record event."""
4555-
4554+
45564555
# To avoid a flood of nearly identical emails, this will do
45574556
# the check only if we have never sent an email, or if we haven't
45584557
# sent one in the last self.time_wait seconds:
4559-
if not self.last_msg_ts or abs(time.time() - self.last_msg_ts) &ge; self.time_wait :
4558+
if not self.last_msg_ts or abs(time.time() - self.last_msg_ts) >= self.time_wait :
45604559
# Get the new archive record:
45614560
record = event.record
4562-
4563-
# Be prepared to catch an exception in the case that the expression contains
4561+
4562+
# Be prepared to catch an exception in the case that the expression contains
45644563
# a variable that is not in the record:
45654564
try: # NOTE 2
45664565
# Evaluate the expression in the context of the event archive record.
@@ -4578,23 +4577,23 @@ <h2 id="Adding_a_service">Adding a service</h2>
45784577

45794578
def soundTheAlarm(self, rec):
45804579
"""This function is called when the given expression evaluates True."""
4581-
4580+
45824581
# Get the time and convert to a string:
45834582
t_str = timestamp_to_string(rec['dateTime'])
45844583

4585-
# Log it in the system log:
4584+
# Log it
45864585
syslog.syslog(syslog.LOG_INFO, "alarm: Alarm expression \"%s\" evaluated True at %s" % (self.expression, t_str))
45874586

45884587
# Form the message text:
45894588
msg_text = "Alarm expression \"%s\" evaluated True at %s\nRecord:\n%s" % (self.expression, t_str, str(rec))
45904589
# Convert to MIME:
45914590
msg = MIMEText(msg_text)
4592-
4591+
45934592
# Fill in MIME headers:
45944593
msg['Subject'] = self.SUBJECT
45954594
msg['From'] = self.FROM
45964595
msg['To'] = ','.join(self.TO)
4597-
4596+
45984597
# Create an instance of class SMTP for the given SMTP host:
45994598
s = smtplib.SMTP(self.smtp_host)
46004599
try:
@@ -4604,26 +4603,27 @@ <h2 id="Adding_a_service">Adding a service</h2>
46044603
s.ehlo()
46054604
s.starttls()
46064605
s.ehlo()
4607-
syslog.syslog(syslog.LOG_DEBUG, " **** using encrypted transport")
4606+
syslog.syslog(syslog.LOG_DEBUG, "alarm: using encrypted transport")
46084607
except smtplib.SMTPException:
4609-
syslog.syslog(syslog.LOG_DEBUG, " **** using unencrypted transport")
4608+
syslog.syslog(syslog.LOG_DEBUG, "alarm: using unencrypted transport")
46104609

46114610
try:
46124611
# If a username has been given, assume that login is required for this host:
46134612
if self.smtp_user:
46144613
s.login(self.smtp_user, self.smtp_password)
4615-
syslog.syslog(syslog.LOG_DEBUG, " **** logged in with user name %s" % (self.smtp_user,))
4616-
4614+
syslog.syslog(syslog.LOG_DEBUG, "alarm: logged in with user name %s" % (self.smtp_user,))
4615+
46174616
# Send the email:
46184617
s.sendmail(msg['From'], self.TO, msg.as_string())
46194618
# Log out of the server:
46204619
s.quit()
46214620
except Exception, e:
46224621
syslog.syslog(syslog.LOG_ERR, "alarm: SMTP mailer refused message with error %s" % (e,))
46234622
raise
4624-
4623+
46254624
# Log sending the email:
4626-
syslog.syslog(syslog.LOG_INFO, " **** email sent to: %s" % self.TO) </pre>
4625+
syslog.syslog(syslog.LOG_INFO, "alarm: email sent to: %s" % self.TO)
4626+
</pre>
46274627

46284628
<p>This service expects all the information it needs to be in the
46294629
configuration file <span class="code">weewx.conf</span> in a new
@@ -4632,11 +4632,11 @@ <h2 id="Adding_a_service">Adding a service</h2>
46324632
<pre class="tty">[Alarm]
46334633
expression = "outTemp &lt; 40.0"
46344634
time_wait = 3600
4635-
smtp_host = smtp.mymailserver.com
4635+
smtp_host = smtp.example.com
46364636
smtp_user = myusername
46374637
smtp_password = mypassword
4638-
mailto = auser@adomain.com, anotheruser@someplace.com
4639-
from = me@mydomain.com
4638+
mailto = auser@example.com, anotheruser@example.com
4639+
from = me@example.com
46404640
subject = "Alarm message from weewx!"</pre>
46414641
<p>There are three important points to be noted in this example, each marked
46424642
with a <span class="code">NOTE</span> flag in the code.</p>
@@ -4690,14 +4690,16 @@ <h2 id="Adding_a_service">Adding a service</h2>
46904690
valid "from" email address and the one <span class="code">weewx</span>
46914691
supplies may not satisfy its requirements. </p>
46924692

4693-
<p>To make this all work, you must tell the engine to load this new
4694-
service by adding the service name to the
4693+
<p>To make this all work, you must first copy the
4694+
<span class="code">alarm.py</span> file to the
4695+
<span class="code">user</span> directory. Then tell the engine to
4696+
load this new service by adding the service name to the
46954697
list <span class="code">report_services</span>,
46964698
located in <span class="code">[Engine][[Services]]</span>: </p>
46974699
<pre class="tty">[Engine]
46984700
[[Services]]
46994701
report_services = weewx.engine.StdPrint, weewx.engine.StdReport<span
4700-
class="highlight">, examples.alarm.MyAlarm</span></pre>
4702+
class="highlight">, user.alarm.MyAlarm</span></pre>
47014703
<p>Again, note that the option <span class="code">report_services</span> must be all on
47024704
one line &mdash; the parser <span class="code">ConfigObj</span>
47034705
does not allow options to be continued on to following lines.</p>

bin/examples/alarm.py examples/alarm.py

+45-43
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,61 @@
1-
#
21
# Copyright (c) 2009-2015 Tom Keffer <[email protected]>
3-
#
4-
# See the file LICENSE.txt for your full rights.
5-
#
2+
# See the file LICENSE.txt for your rights.
3+
64
"""Example of how to implement an alarm in weewx.
75
8-
********************************************************************************
6+
*******************************************************************************
97
10-
To use this alarm, add the following somewhere in your configuration file
11-
weewx.conf:
8+
To use this alarm, add the following to the weewx configuration file:
129
1310
[Alarm]
14-
expression = "outTemp < 40.0"
15-
time_wait = 3600
16-
smtp_host = smtp.mymailserver.com
17-
smtp_user = myusername
18-
smtp_password = mypassword
19-
mailto = [email protected], anotheruser@someplace.com
20-
from = me@mydomain.com
21-
subject = "Alarm message from weewx!"
11+
expression = "outTemp < 40.0"
12+
time_wait = 3600
13+
smtp_host = smtp.example.com
14+
smtp_user = myusername
15+
smtp_password = mypassword
16+
from = sally@example.com
17+
mailto = [email protected], bob@example.com
18+
subject = "Alarm message from weewx!"
2219
2320
In this example, if the outside temperature falls below 40, it will send an
24-
email to the the comma separated list specified in option "mailto", in this case
25-
21+
email to the users specified in the comma separated list specified in option
22+
"mailto", in this case:
23+
24+
2625
27-
The example assumes that your SMTP email server is at smtp.mymailserver.com and
28-
that it uses secure logins. If it does not use secure logins, leave out the
29-
lines for smtp_user and smtp_password and no login will be attempted.
26+
The example assumes an SMTP email server at smtp.example.com that requires
27+
login. If the SMTP server does not require login, leave out the lines for
28+
smtp_user and smtp_password.
3029
31-
Setting an email "from" is optional. If not supplied, one will be filled in, but
32-
your SMTP server may or may not accept it.
30+
Setting an email "from" is optional. If not supplied, one will be filled in,
31+
but your SMTP server may or may not accept it.
3332
3433
Setting an email "subject" is optional. If not supplied, one will be filled in.
3534
36-
To avoid a flood of emails, one will only be sent every 3600 seconds (one hour).
35+
To avoid a flood of emails, one will only be sent every 3600 seconds (one
36+
hour).
37+
38+
*******************************************************************************
39+
40+
To enable this service:
3741
38-
********************************************************************************
42+
1) copy this file to the user directory
3943
40-
To specify that this new service be loaded and run, it must be added to the
41-
configuration option "report_services", located in sub-section [Engine][[Services]].
44+
2) modify the weewx configuration file by adding this service to the option
45+
"report_services", located in section [Engine][[Services]].
4246
4347
[Engine]
4448
[[Services]]
4549
...
46-
report_services = weewx.engine.StdPrint, weewx.engine.StdReport, examples.alarm.MyAlarm
50+
report_services = weewx.engine.StdPrint, weewx.engine.StdReport, user.alarm.MyAlarm
4751
48-
********************************************************************************
52+
*******************************************************************************
4953
50-
If you wish to use both this example and the lowBattery.py example, simply merge
51-
the two configuration options together under [Alarm] and add both services to
52-
report_services.
54+
If you wish to use both this example and the lowBattery.py example, simply
55+
merge the two configuration options together under [Alarm] and add both
56+
services to report_services.
5357
54-
********************************************************************************
58+
*******************************************************************************
5559
"""
5660

5761
import time
@@ -66,7 +70,7 @@
6670

6771
# Inherit from the base class StdService:
6872
class MyAlarm(StdService):
69-
"""Custom service that sounds an alarm if an arbitrary expression evaluates true"""
73+
"""Service that sends email if an arbitrary expression evaluates true"""
7074

7175
def __init__(self, engine, config_dict):
7276
# Pass the initialization information on to my superclass:
@@ -85,15 +89,14 @@ def __init__(self, engine, config_dict):
8589
self.smtp_user = config_dict['Alarm'].get('smtp_user')
8690
self.smtp_password = config_dict['Alarm'].get('smtp_password')
8791
self.SUBJECT = config_dict['Alarm'].get('subject', "Alarm message from weewx")
88-
self.FROM = config_dict['Alarm'].get('from', 'alarm@weewx.com')
92+
self.FROM = config_dict['Alarm'].get('from', 'alarm@example.com')
8993
self.TO = option_as_list(config_dict['Alarm']['mailto'])
9094
syslog.syslog(syslog.LOG_INFO, "alarm: Alarm set for expression: '%s'" % self.expression)
9195

9296
# If we got this far, it's ok to start intercepting events:
9397
self.bind(weewx.NEW_ARCHIVE_RECORD, self.newArchiveRecord) # NOTE 1
94-
9598
except KeyError, e:
96-
syslog.syslog(syslog.LOG_INFO, "alarm: No alarm set. %s" % e)
99+
syslog.syslog(syslog.LOG_INFO, "alarm: No alarm set. Missing parameter: %s" % e)
97100

98101
def newArchiveRecord(self, event):
99102
"""Gets called on a new archive record event."""
@@ -127,7 +130,7 @@ def soundTheAlarm(self, rec):
127130
# Get the time and convert to a string:
128131
t_str = timestamp_to_string(rec['dateTime'])
129132

130-
# Log it in the system log:
133+
# Log it
131134
syslog.syslog(syslog.LOG_INFO, "alarm: Alarm expression \"%s\" evaluated True at %s" % (self.expression, t_str))
132135

133136
# Form the message text:
@@ -149,15 +152,15 @@ def soundTheAlarm(self, rec):
149152
s.ehlo()
150153
s.starttls()
151154
s.ehlo()
152-
syslog.syslog(syslog.LOG_DEBUG, " **** using encrypted transport")
155+
syslog.syslog(syslog.LOG_DEBUG, "alarm: using encrypted transport")
153156
except smtplib.SMTPException:
154-
syslog.syslog(syslog.LOG_DEBUG, " **** using unencrypted transport")
157+
syslog.syslog(syslog.LOG_DEBUG, "alarm: using unencrypted transport")
155158

156159
try:
157160
# If a username has been given, assume that login is required for this host:
158161
if self.smtp_user:
159162
s.login(self.smtp_user, self.smtp_password)
160-
syslog.syslog(syslog.LOG_DEBUG, " **** logged in with user name %s" % (self.smtp_user,))
163+
syslog.syslog(syslog.LOG_DEBUG, "alarm: logged in with user name %s" % (self.smtp_user,))
161164

162165
# Send the email:
163166
s.sendmail(msg['From'], self.TO, msg.as_string())
@@ -168,15 +171,15 @@ def soundTheAlarm(self, rec):
168171
raise
169172

170173
# Log sending the email:
171-
syslog.syslog(syslog.LOG_INFO, " **** email sent to: %s" % self.TO)
174+
syslog.syslog(syslog.LOG_INFO, "alarm: email sent to: %s" % self.TO)
175+
172176

173177
if __name__ == '__main__':
174178
"""This section is used for testing the code. """
175179
import sys
176180
import configobj
177181
from optparse import OptionParser
178182

179-
180183
usage_string ="""Usage:
181184
182185
alarm.py config_path
@@ -215,4 +218,3 @@ def soundTheAlarm(self, rec):
215218

216219
event = weewx.Event(weewx.NEW_ARCHIVE_RECORD, record=rec)
217220
alarm.newArchiveRecord(event)
218-

0 commit comments

Comments
 (0)