pywws-24.2.0/0000755000200200001440000000000014556655656012744 5ustar jimusers00000000000000pywws-24.2.0/.gitignore0000644000200200001440000000035214556653422014721 0ustar jimusers00000000000000.gitignore *.py[co] # Packages *.egg *.egg-info dist build eggs parts bin var sdist develop-eggs .installed.cfg # Editor backups *~ # Compiled documentation /doc /src/doc/api/pywws.*.rst # Compiled language files *.mo *.stackdump pywws-24.2.0/.readthedocs.yaml0000644000200200001440000000071214556653422016160 0ustar jimusers00000000000000# Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the version of Python and other tools you might need build: os: ubuntu-20.04 tools: python: "3" # Build documentation in the docs/ directory with Sphinx sphinx: builder: html configuration: src/doc/conf.py python: install: - method: pip path: . - requirements: src/doc/requirements.txt pywws-24.2.0/.tx/0000755000200200001440000000000014556655656013455 5ustar jimusers00000000000000pywws-24.2.0/.tx/config0000644000200200001440000000214014371663116014623 0ustar jimusers00000000000000[main] host = https://www.transifex.com [o:jim-easterbrook:p:pywws:r:api] file_filter = src/pywws/lang//LC_MESSAGES/api.po source_file = build/gettext/api.pot source_lang = en [o:jim-easterbrook:p:pywws:r:api_index] file_filter = src/pywws/lang//LC_MESSAGES/api_index.po source_file = build/gettext/api_index.pot source_lang = en [o:jim-easterbrook:p:pywws:r:copyright] file_filter = src/pywws/lang//LC_MESSAGES/copyright.po source_file = build/gettext/copyright.pot source_lang = en [o:jim-easterbrook:p:pywws:r:essentials] file_filter = src/pywws/lang//LC_MESSAGES/essentials.po source_file = build/gettext/essentials.pot source_lang = en [o:jim-easterbrook:p:pywws:r:guides] file_filter = src/pywws/lang//LC_MESSAGES/guides.po source_file = build/gettext/guides.pot source_lang = en [o:jim-easterbrook:p:pywws:r:index] file_filter = src/pywws/lang//LC_MESSAGES/index.po source_file = build/gettext/index.pot source_lang = en [o:jim-easterbrook:p:pywws:r:pywws] file_filter = src/pywws/lang//LC_MESSAGES/pywws.po source_file = build/gettext/pywws.pot source_lang = en pywws-24.2.0/CHANGELOG.txt0000644000200200001440000003604514556655121014767 0ustar jimusers00000000000000pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-24 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Changes in v24.2.0: 1/ Ignore data changes that happen when pointer changes. 2/ Python 3.11 compatibility. Changes in v22.10.0: 1/ Reduced incidence of CWOP service timeout errors. Changes in v22.9.0: 1/ Reject data if 'pointer' value is invalid due to failing hardware. 2/ Updated Weather Underground uploader documentation. Changes in v22.3.0: 1/ Replace pytz with dateutil.tz. 2/ Fix some hidapi USB problems. 3/ Correct some typos in documentation. Changes in v21.4.0: 1/ Fixed problems with timezones ready for next release of tzlocal. 2/ Fixed rare problem with 'saved_date' being 'None'. Changes in v21.3.0: 1/ Added -d option to pywws-setweatherstation. This is useful if your station sets loads of alarms after a reset. 2/ Updated pywws.timezone to cope with changes in Python 3.6. 3/ Various bug fixes and minor improvements. Changes in v20.1.0: 1/ Added a "Windy" service uploader module. 2/ Various bug fixes and minor improvements. Changes in v19.7.1: 1/ Fix file data iteration bug introduced in v19.7.0. Changes in v19.7.0: 1/ Update default template_txt for service.mqtt to provide wider range of values out of the box. The published format is not backwards compatible, but this only affects new users. 2/ Improved reliability with "solar" stations when lost contact with solar sensors. 3/ Some file data errors should now be detected and a log message sent. Changes in v19.4.0: 1/ Can optionally use SQLite3 data store instead of CSV files. 2/ Improve weathercloud service uploader. 3/ Cope slightly better with stations that aren't logging data. Changes in v18.10.1: 1/ Fix bug when running a service directly (in Python 2 only) introduced in v18.9.0. Changes in v18.10.0: 1/ Fix template loop bug (in Python 2 only) introduced in v18.9.0. Changes in v18.9.0: 1/ Major changes to ftp uploads. New ftp/sftp/copy services do the uploading. pywws should make the required changes to weather.ini automatically, but users should check after running v18.9.0 for the first time. 2/ New services to post to Mastodon and WeatherCloud. 3/ MQTT service can now use TLS. 4/ Various bug fixes and minor improvements. Changes in v18.6.3: 1/ Restore Python source text encoding comments needed by some Python 2 versions. 2/ Add example AWS uploader module from Chris Ramsay. Changes in v18.6.2: 1/ Fix duplicate data bug in live logging. Changes in v18.6.1: 1/ Fix bug in "fixed block" date parsing. Changes in v18.6.0: 1/ Substantial rewrite of much of pywws. It is now more "standard" in many ways, such as names of modules, and is compatible with Python 2.7 and 3. 2/ New "service" uploaders. "underground_rf" and "cwop_ham" have been merged in to "underground" and "cwop". 3/ "Day end hour" can now vary with daylight savings time. 4/ Improved reliability with "3080" class stations. 5/ Various other bug fixes and minor improvements. Changes in v18.04.1: 1/ Fix bug in utc <-> local time conversions. Changes in v18.04.0: 1/ Now works with broken weather stations that have stopped logging data. (Although there may be more gaps in the data.) 2/ Cope better with missing wind direction data. 3/ Use HTTPS for Weather Underground uploads. 4/ Other minor bug fixes. Changes in v17.11.0: 1/ Allow MQTT service without password. 2/ Allow SFTP uploads with public key. 3/ Increase Twitter character limit from 140 to 280. 4/ Various other bug fixes and minor improvements. Changes in v16.12.0: 1/ Added "candlestick" plot type. 2/ Added cloud base calculation function. 3/ Various other bug fixes and minor improvements. Changes in v16.08.0: 1/ Fix Python 2.5 incompatibilities. 2/ Fix python-twitter v3 tweet length problem. Changes in v16.07.1: 1/ Further changes to handle UK Met Office server quirks. Changes in v16.07.0: 1/ Fix bug with UK Met Office uploads server change. 2/ Allow user commands in wind roses. 3/ Various other bug fixes and minor improvements. Changes in v15.12.0: 1/ Fix bug with Twitter messages being excessively truncated. 2/ Improve handling of utf-8 encoded templates. 3/ Improved plots and wind roses with 'pngcairo' "terminal". 4/ Various bug fixes and minor improvements. Changes in v15.11.0: 1/ Add Russian translation of program text. 2/ Improved documentation. 3/ Various bug fixes and minor improvements. Changes in v15.07.0: 1/ Can include multiple media in Twitter messages. 2/ Attempt to fix bug in wind rose axes labels. 3/ Enable inclusion of time & date in wind rose title. 4/ Various bug fixes and minor improvements. Changes in v15.01.0: 1/ Added 'MQTT' service. 2/ Added another USB library option. 3/ Improved Python 3 compatibility. 4/ Various bug fixes and minor improvements. Changes in v14.12.0: 1/ Updated temperatur.nu and wetterarchiv.de service details to suit new APIs. Changes in v14.06.1: 1/ Revised version numbering scheme. 2/ Compiled documentation no longer included in releases. 3/ Can partially specify start & stop date/time in graphs, e.g. to start a plot at midnight, no matter when it is plotted. Changes in v14.06: 1/ Can now send images to Twitter. 2/ Periodic tasks can be specified with a cron style syntax. 3/ Added wind direction filter for use in graphs or user calibration modules. 4/ Wind direction is now stored as a float. Old templates that use the wind_dir_text array will need updating, probably to use the winddir_text() function. 5/ Started using "Transifex" to host translations. Changed tools and procedures to create new translations. 6/ Improved USB hangup avoidance strategy for stations with large clock drift figures. 7/ Various bug fixes and minor improvements. Changes in v14.05: 1/ Rearranged package layout, moving examples and documentation. 2/ Added 'entry point' auto-generated commands for some modules. 3/ Added verbose output option to pywws-version command. 4/ Various bug fixes and minor improvements. Changes in v14.03: 1/ Extracts additional status from 'wind_dir' byte. You must run pywws-reprocess.py with the -u option after upgrading from any previous version. 2/ Added Citizen Weather Observer Program to available 'services'. 3/ Improved asynchronous upload task queuing. 4/ Various bug fixes and minor improvements. Changes in v14.02: 1/ Improved time zone handling, including non whole hour time zones. 2/ New 'frequent writes' config option. 3/ Improved 'live log' sync, particularly with 3080 type stations. 4/ Record recent memory pointer to improve detection of gaps in data. 5/ Various bug fixes and minor improvements. Changes in v13.12: 1/ Changed API of user calibration module. 2/ Can use python-twitter *or* tweepy library. 3/ Added a script to run live logging as a UNIX daemon process. 4/ Changed data store to use separate read and write caches. 5/ Various bug fixes and minor improvements. Changes in v13.10: 1/ Changed Twitter library from tweepy to python-twitter. 2/ Added ability to do uploads asynchronously. 3/ Rearranged and improved documentation. 4/ Various bug fixes and minor improvements. Changes in v13.06: 1/ Substantially rearranged directories, getting rid of 'code' and 'code3'. 2/ Removed 'makefile' - everything is now done via 'setup.py'. 3/ Removed 'RunModule.py' - use 'python -m pywws.module' now. 4/ Separated storage of config (weather.ini) and status (status.ini). 5/ Replaced toservice.py "rapid fire" mode with a separate config file for Weather Underground rapid fire. 6/ Added 2 more low-level USB access modules. 7/ Various bug fixes and minor improvements. Changes in v13.03: 1/ Added 'rain days' to monthly data. (Reprocess required when upgrading.) 2/ Extended template syntax to include comments. 3/ Added 'humidity index' function. 4/ Added French translation of documentation. 5/ Reduced frequency of saving data files. 6/ Various bug fixes. Changes in v12.12: 1/ Added support for Python 3. 2/ Added French documentation translation. 3/ Used 'binary search' to speed up data access. 4/ Various bug fixes. Changes in v12.11: 1/ Moved development from Google code to GitHub. 2/ Made software attempt to avoid USB activity at times when it is assumed the weather station might be writing to its memory. This might solve the USB lockup problem, but it's too early to tell. Changes in v12.10: 1/ Added a 'winddir_text' function for use in templates. 2/ Added and options to graph plots. 3/ Various bug fixes. Changes in v12.07: 1/ Added Open Weather Map to the services. 2/ Fixed problem with Weather Underground uploads that started on 1st June. 3/ Various bug fixes and software structure improvements. Changes in v12.05: 1/ Made 'fixed block' data available to template calculations. 2/ Fixed buggy auto-detection of 3080 weather stations. 3/ Added a function to generate the Zambretti forecast code letter. 4/ Added a program to test USB communication reliablility. 5/ Various bug fixes and software structure improvements. Changes in v12.02: 1/ Separated out low level USB communications to enable use of different libraries. Now works on recent versions of Mac OS. 2/ Added humidity, pressure & wind data to summary data. 3/ Merged Weather Underground and UK Met Office uploaders into one combined module. Added more 'service' uploaders. 4/ Various bug fixes and software structure improvements. Changes in v11.10: 1/ Complete restructuring of documentation. 2/ Added a user defined 'calibration' process. 3/ Sets 'locale' according to language setting. 4/ Added ability to upload to UK Met Office 'WOW'. 5/ Various bug fixes and software structure improvements. 6/ New language files: French, Danish. Changes in v11.05: 1/ Added support for '3080' family stations that have illuminance and UV sensors. 2/ Broadened the range of tasks that can be done with 'live' data. 3/ Various bug fixes and software structure improvements. Changes in v11.02: 1/ Various bug fixes and software structure improvements. 2/ Improved wind direction averaging. 3/ Added conversion functions for common things such as C to F. 4/ Added a YoWindow module. 5/ Improved Zambretti forecaster. Changes in v10.12: 1/ Various bug fixes and software structure improvements. 2/ Added a 'goto' instruction to Template.py. 3/ Added a 'Zambretti' forecast function to Template.py. This should be treated as an experiment, and not relied upon for accuracy. Changes in v10.10: 1/ Added 'catchup' mode to ToUnderground.py. 2/ Created 'Tasks.py' to handle common tasks. 3/ Made better use of Python's logger for info and error messages. 4/ Changed over from 'python-twitter' to 'tweepy' for Twitter access. Twitter authorisation using OAuth now works. 5/ Added 'LiveLog.py' live logging program. 6/ Added 'SetWeatherStation.py' to do some configuration of weather station. No longer need EasyWeather to set logging interval! 7/ Added 'Rapid Fire' ability to ToUnderground.py. 8/ Added plain text versions of HTML documentation. 9/ Many bug fixes and minor improvements. Changes in v10.08: 1/ Added internal temperature to daily and monthly summaries. Run Reprocess.py when upgrading from earlier versions. 2/ Added 'prevdata' to Template.py. Allows calculations that compare values from different times. 3/ Made 'pressure_offset' available to calculations in Plot.py and Template.py. This is only useful when using 'raw' data. 4/ Improved synchronisation to weather station's clock when fetching stored data. Changes in v10.06: 1/ Improved localisation code. 2/ Minor bug fixes. 3/ Added Y axis label angle control to plots. Changes in v10.04: 1/ Changed version numbering to year.month. 2/ Allowed "upload" to a local directory instead of ftp site. 3/ Added "calc" option to text templates (Template.py). 4/ Added -v / --verbose option to Hourly.py to allow silent operation. 5/ Added internationalisation / localisation of some strings. 6/ Made 'raw' data available to text templates. 7/ Added ability to upload to Weather Underground. 8/ Added dual axis and cumulative graph capability. Changes in v0.9: 1/ Added lowest daytime max and highest nighttime min temperatures to monthly data. 2/ Added average temperature to daily and monthly data. 3/ Added 'terminal' element to Plot.py templates for greater control over output appearance. 4/ Added 'command' element to Plot.py templates for even more control, for advanced users. 5/ Added secure upload option. 6/ Minor speed improvements. Changes in v0.8: 1/ Added meteorological day end hour user preference 2/ Attempts at Windows compatibility 3/ Corrected decoding of wind data at speeds over 25.5 m/s 4/ Improved speed with new data caching strategy Changes in v0.7: 1/ Several bug fixes, mostly around new weather stations with not much data 2/ Added min & max temperature extremes to monthly data 3/ Added template and workspace directory locations to weather.ini 4/ Increased versatility of Plot.py with layout and title elements Changes in v0.6: 1/ Added monthly data 2/ Changed 'pressure' to 'abs_pressure' or 'rel_pressure' Changes in v0.5: 1/ Small bug fixes. 2/ Added start time to daily data 3/ Replaced individual plot programs with XML "recipe" system Changes in v0.4: 1/ Can post brief messages to Twitter. 2/ Now time zone aware. Uses UTC for data indexing and local time for graphs and text data files. Changes in v0.3: 1/ Now uses templates to generate text data 2/ Added 28 day plot 3/ Minor efficiency improvements 4/ Improved documentation Changes in v0.2: 1/ Now uses Python csv library to read and write data 2/ Creates hourly and daily summary files 3/ Includes rain data in graphs pywws-24.2.0/CONTRIBUTING.rst0000644000200200001440000000614212545440515015366 0ustar jimusers00000000000000Contributing to pywws ##################### If you would like to add a feature to pywws (or fix a problem with it) then please do. Open source software thrives when its users become active contributors. The process is quite simple: #. Join `GitHub `_ - it's free. #. Fork the pywws repo - see `Fork a Repo `_ for help. #. Clone your fork to a computer you can use to develop your new feature. #. Use git to commit changes as you make them and push the changes to your fork of pywws. Please add a signed-off-by line to your commits which certify your developer certificate of origin (see below). For example, if your name is “John Smith”, and your email address is "jsmith@example.com", just include the following line at the bottom of your commit messages: Signed-off-by: John Smith You should be able to do this automatically by using the ``-s`` option on your ``git commit`` commands. #. Add your name and email to the ``src/contributors/contributors.txt`` file. Don't forget the ``-s`` option when you commit this change. #. Test your changes! #. When everything's working as you expect, submit a `Pull Request `_. Developer Certificate of Origin ------------------------------- Including a signed-off-by line in your commits indicates that you certify the following:: Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 660 York Street, Suite 102, San Francisco, CA 94110 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. Clauses (a), (b) and (c) reassure pywws users that the project will remain open source well in to the future. Clause (d) reminds you that your contributions will be publicly available, and you do not have the right to withdraw them in future. pywws-24.2.0/LICENCE.txt0000644000200200001440000004312212250320403014511 0ustar jimusers00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. pywws-24.2.0/MANIFEST.in0000644000200200001440000000021512443025454014454 0ustar jimusers00000000000000include *.txt recursive-include .tx * include doc/*.html recursive-include src/doc * recursive-include src/pywws/lang *.po prune src/doc/api pywws-24.2.0/PKG-INFO0000644000200200001440000001434414556655656014047 0ustar jimusers00000000000000Metadata-Version: 2.1 Name: pywws Version: 24.2.0 Summary: Python software for wireless weather stations Home-page: https://github.com/jim-easterbrook/pywws/ Author: Jim Easterbrook Author-email: jim@jim-easterbrook.me.uk License: GNU GPL Download-URL: https://pypi.python.org/pypi/pywws/24.2.0 Platform: POSIX Platform: MacOS Platform: Windows Classifier: Development Status :: 6 - Mature Classifier: Intended Audience :: End Users/Desktop Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2) Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Provides-Extra: daemon Provides-Extra: sftp Provides-Extra: twitter License-File: LICENCE.txt .. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-18 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. pywws ##### Python software for USB Wireless Weather Stations. pywws is a collection of Python modules to read, store and process data from popular USB wireless weather stations such as Elecsa AstroTouch 6975, Watson W-8681, WH-1080PC, WH1080, WH1081, WH3080 etc. I assume any model that is supplied with the EasyWeather Windows software is compatible, but cannot guarantee this. The software has been developed to run in a low power, low memory environment such as a `Raspberry Pi`_. It can be used to create graphs and web pages showing recent weather readings, typically updated every hour. It can also send "live" data to services such as `Weather Underground`_ and post messages to Twitter_. The development version of pywws is hosted on GitHub. * https://github.com/jim-easterbrook/pywws "Snapshot" releases of pywws are available from the `Python Package Index`_ (PyPI). * https://pypi.org/project/pywws/ Documentation is hosted on `Read the Docs`_. * http://pywws.readthedocs.io/ I have written this software to meet my needs, but have tried to make it adaptable to other people's requirements. You may want to edit some or all of the modules, or write some new ones, to get it to do exactly what you want. One of the reasons for using Python is that it makes such alterations so easy. Don't be afraid, just jump in and have a go. Requirements ============ The software needed to run pywws depends on what you plan to do with it. You'll need some of the following. * Essential: Python_ 2.7 or 3 (also see `legacy version`_ below). * Essential: USB library `python-libusb1`_ or PyUSB_ or, for MacOS, hidapi_ and a Python interface to it. * Graph drawing: gnuplot_. * Secure uploading to your web site: Paramiko_. * Posting to Twitter_: `python-twitter`_ or Tweepy_. * Posting to other web services: `python-requests`_. For more detail, see the documentation - dependencies_. Legacy version -------------- If for some reason you are stuck with Python 2.5 or 2.6 a "`legacy branch`_" of pywws can be installed with pip and is available on GitHub. The most recent version of this branch is 18.4.1. .. placeholder-credits Credits ======= I would not have been able to get any information from the weather station without access to the source of Michael Pendec's "wwsr" program. I am also indebted to Dave Wells for decoding the weather station's "`fixed block data`_". Last of all, a big thank you to all the pywws users who have helped with questions and suggestions, and especially to those who have translated pywws and its documentation into other languages. Legalese ======== | pywws - Python software for USB Wireless Weather Stations. | https://github.com/jim-easterbrook/pywws | Copyright (C) 2008-18 `pywws contributors`_ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the `GNU General Public License`_ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA .. _dependencies: http://pywws.readthedocs.io/en/latest/essentials/dependencies.html .. _how to get started with pywws: http://pywws.readthedocs.io/en/latest/guides/getstarted.html .. _pywws contributors: http://pywws.readthedocs.io/en/latest/copyright.html .. _fixed block data: http://www.jim-easterbrook.me.uk/weather/mm/ .. _GNU General Public License: http://pywws.readthedocs.io/en/latest/essentials/LICENCE.html .. _gnuplot: http://www.gnuplot.info/ .. _hidapi: http://www.signal11.us/oss/hidapi/ .. _legacy branch: https://pypi.org/project/pywws/18.4.1/ .. _Paramiko: https://pypi.org/project/paramiko/ .. _pip: https://pypi.org/project/pip/ .. _Python: https://www.python.org/ .. _Python Package Index: https://pypi.org/project/pywws/ .. _python-libusb1: https://pypi.org/project/libusb1/ .. _python-requests: https://pypi.org/project/requests/ .. _python-twitter: https://pypi.org/project/python-twitter/ .. _PyUSB: https://pypi.org/project/pyusb/ .. _pywws Google mailing list: http://groups.google.com/group/pywws .. _Raspberry Pi: https://www.raspberrypi.org/ .. _Read the Docs: http://pywws.readthedocs.io/ .. _Tweepy: https://pypi.org/project/tweepy/ .. _Twitter: https://twitter.com/ .. _Weather Underground: https://www.wunderground.com/ pywws-24.2.0/README.rst0000644000200200001440000001270113305436032014404 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-18 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. pywws ##### Python software for USB Wireless Weather Stations. pywws is a collection of Python modules to read, store and process data from popular USB wireless weather stations such as Elecsa AstroTouch 6975, Watson W-8681, WH-1080PC, WH1080, WH1081, WH3080 etc. I assume any model that is supplied with the EasyWeather Windows software is compatible, but cannot guarantee this. The software has been developed to run in a low power, low memory environment such as a `Raspberry Pi`_. It can be used to create graphs and web pages showing recent weather readings, typically updated every hour. It can also send "live" data to services such as `Weather Underground`_ and post messages to Twitter_. The development version of pywws is hosted on GitHub. * https://github.com/jim-easterbrook/pywws "Snapshot" releases of pywws are available from the `Python Package Index`_ (PyPI). * https://pypi.org/project/pywws/ Documentation is hosted on `Read the Docs`_. * http://pywws.readthedocs.io/ I have written this software to meet my needs, but have tried to make it adaptable to other people's requirements. You may want to edit some or all of the modules, or write some new ones, to get it to do exactly what you want. One of the reasons for using Python is that it makes such alterations so easy. Don't be afraid, just jump in and have a go. Requirements ============ The software needed to run pywws depends on what you plan to do with it. You'll need some of the following. * Essential: Python_ 2.7 or 3 (also see `legacy version`_ below). * Essential: USB library `python-libusb1`_ or PyUSB_ or, for MacOS, hidapi_ and a Python interface to it. * Graph drawing: gnuplot_. * Secure uploading to your web site: Paramiko_. * Posting to Twitter_: `python-twitter`_ or Tweepy_. * Posting to other web services: `python-requests`_. For more detail, see the documentation - dependencies_. Legacy version -------------- If for some reason you are stuck with Python 2.5 or 2.6 a "`legacy branch`_" of pywws can be installed with pip and is available on GitHub. The most recent version of this branch is 18.4.1. .. placeholder-credits Credits ======= I would not have been able to get any information from the weather station without access to the source of Michael Pendec's "wwsr" program. I am also indebted to Dave Wells for decoding the weather station's "`fixed block data`_". Last of all, a big thank you to all the pywws users who have helped with questions and suggestions, and especially to those who have translated pywws and its documentation into other languages. Legalese ======== | pywws - Python software for USB Wireless Weather Stations. | https://github.com/jim-easterbrook/pywws | Copyright (C) 2008-18 `pywws contributors`_ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the `GNU General Public License`_ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA .. _dependencies: http://pywws.readthedocs.io/en/latest/essentials/dependencies.html .. _how to get started with pywws: http://pywws.readthedocs.io/en/latest/guides/getstarted.html .. _pywws contributors: http://pywws.readthedocs.io/en/latest/copyright.html .. _fixed block data: http://www.jim-easterbrook.me.uk/weather/mm/ .. _GNU General Public License: http://pywws.readthedocs.io/en/latest/essentials/LICENCE.html .. _gnuplot: http://www.gnuplot.info/ .. _hidapi: http://www.signal11.us/oss/hidapi/ .. _legacy branch: https://pypi.org/project/pywws/18.4.1/ .. _Paramiko: https://pypi.org/project/paramiko/ .. _pip: https://pypi.org/project/pip/ .. _Python: https://www.python.org/ .. _Python Package Index: https://pypi.org/project/pywws/ .. _python-libusb1: https://pypi.org/project/libusb1/ .. _python-requests: https://pypi.org/project/requests/ .. _python-twitter: https://pypi.org/project/python-twitter/ .. _PyUSB: https://pypi.org/project/pyusb/ .. _pywws Google mailing list: http://groups.google.com/group/pywws .. _Raspberry Pi: https://www.raspberrypi.org/ .. _Read the Docs: http://pywws.readthedocs.io/ .. _Tweepy: https://pypi.org/project/tweepy/ .. _Twitter: https://twitter.com/ .. _Weather Underground: https://www.wunderground.com/ pywws-24.2.0/setup.cfg0000644000200200001440000000004614556655656014565 0ustar jimusers00000000000000[egg_info] tag_build = tag_date = 0 pywws-24.2.0/setup.py0000644000200200001440000001760114556653422014450 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-23 pywws contributors # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. from __future__ import with_statement from datetime import date from distutils.command.upload import upload import os from setuptools import setup import sys # read current version info without importing pywws package if sys.version_info[0] >= 3: with open('src/pywws/__init__.py') as f: exec(f.read()) else: execfile('src/pywws/__init__.py') # get GitHub repo information # requires GitPython - 'sudo pip install gitpython' try: import git except ImportError: git = None if git: try: repo = git.Repo() if repo.is_dirty(): latest = 0 last_release = None for tag in repo.tags: if tag.tag.tagged_date > latest: latest = tag.tag.tagged_date last_release = str(tag) last_commit = str(repo.head.commit)[:7] # regenerate version info, if required if last_commit != _commit: _release = str(int(_release) + 1) _commit = last_commit if last_release: major, minor, patch = map(int, last_release.split('.')) today = date.today() year = today.year % 100 if year == major and today.month == minor: patch += 1 else: patch = 0 __version__ = '{:d}.{:d}.{:d}'.format(year, today.month, patch) with open('src/pywws/__init__.py', 'r') as vf: old_init_str = vf.read() new_init_str = "__version__ = '" + __version__ + "'\n" new_init_str += "_release = '" + _release + "'\n" new_init_str += "_commit = '" + _commit + "'\n" if new_init_str != old_init_str: with open('src/pywws/__init__.py', 'w') as vf: vf.write(new_init_str) except (git.exc.InvalidGitRepositoryError, git.exc.GitCommandNotFound): pass cmdclass = {} command_options = {} if 'LANG' in os.environ: lang = os.environ['LANG'].split('_')[0] else: lang = 'en' # add commands to create & build translation files # requires Babel to be installed command_options['compile_catalog'] = { 'domain' : ('setup.py', 'pywws'), 'directory' : ('setup.py', 'src/pywws/lang'), 'use_fuzzy' : ('setup.py', '1'), } command_options['extract_messages'] = { 'input_dirs' : ('setup.py', 'src/pywws'), 'output_file' : ('setup.py', 'build/gettext/pywws.pot'), 'no_wrap' : ('setup.py', '1'), 'sort_by_file' : ('setup.py', '1'), 'add_comments' : ('setup.py', 'TX_NOTE'), 'strip_comments' : ('setup.py', '1'), 'copyright_holder' : ('setup.py', 'Jim Easterbrook'), 'msgid_bugs_address' : ('setup.py', 'jim@jim-easterbrook.me.uk'), } command_options['init_catalog'] = { 'domain' : ('setup.py', 'pywws'), 'input_file' : ('setup.py', 'build/gettext/pywws.pot'), 'output_dir' : ('setup.py', 'src/pywws/lang'), 'no_wrap' : ('setup.py', '1'), } command_options['update_catalog'] = { 'domain' : ('setup.py', 'pywws'), 'input_file' : ('setup.py', 'build/gettext/pywws.pot'), 'output_dir' : ('setup.py', 'src/pywws/lang'), 'no_wrap' : ('setup.py', '1'), } # if sphinx is installed, add commands to build documentation try: from sphinx.setup_command import BuildDoc # compile documentation to html cmdclass['build_sphinx'] = BuildDoc command_options['build_sphinx'] = { 'source_dir' : ('setup.py', 'src/doc'), 'build_dir' : ('setup.py', 'doc'), 'builder' : ('setup.py', 'html'), } # extract strings for translation class extract_messages_doc(BuildDoc): description = 'extract localizable strings from the documentation' cmdclass['extract_messages_doc'] = extract_messages_doc command_options['extract_messages_doc'] = { 'source_dir' : ('setup.py', 'src/doc'), 'build_dir' : ('setup.py', 'build'), 'builder' : ('setup.py', 'gettext'), } except ImportError: pass # set options for uploading documentation to PyPI command_options['upload_docs'] = { 'upload_dir' : ('setup.py', 'doc'), } # modify upload class to add appropriate tag # requires GitPython - 'sudo pip install gitpython' class upload_and_tag(upload): def run(self): result = upload.run(self) import git message = __version__ + '\n\n' with open('CHANGELOG.txt') as cl: while not cl.readline().startswith('Changes'): pass while True: line = cl.readline().strip() if not line: break message += line + '\n' repo = git.Repo() tag = repo.create_tag(__version__, message=message) remote = repo.remotes.origin remote.push(tags=True) return result cmdclass['upload'] = upload_and_tag # set options for building distributions command_options['sdist'] = { 'formats' : ('setup.py', 'gztar'), } with open('README.rst') as ldf: long_description = ldf.read() setup(name = 'pywws', version = __version__, description = 'Python software for wireless weather stations', author = 'Jim Easterbrook', author_email = 'jim@jim-easterbrook.me.uk', url = 'https://github.com/jim-easterbrook/pywws/', download_url = 'https://pypi.python.org/pypi/pywws/' + __version__, long_description = long_description, classifiers = [ 'Development Status :: 6 - Mature', 'Intended Audience :: End Users/Desktop', 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', ], license = 'GNU GPL', platforms = ['POSIX', 'MacOS', 'Windows'], packages = ['pywws', 'pywws.service'], package_dir = {'' : 'src'}, package_data = { 'pywws' : [ 'services/*', 'lang/*/LC_MESSAGES/pywws.mo', 'examples/*/*.*', 'examples/*/*/*.*', ], }, cmdclass = cmdclass, command_options = command_options, entry_points = { 'console_scripts' : [ 'pywws-hourly = pywws.hourly:main', 'pywws-livelog = pywws.livelog:main', 'pywws-livelog-daemon = pywws.livelogdaemon:main', 'pywws-reprocess = pywws.reprocess:main', 'pywws-setweatherstation = pywws.setweatherstation:main', 'pywws-testweatherstation = pywws.testweatherstation:main', 'pywws-version = pywws.version:main', ], }, install_requires = ['python-dateutil'], extras_require = { 'daemon' : ['python-daemon == 2.1.2'], 'sftp' : ['paramiko', 'pycrypto'], 'twitter' : ['python-twitter >= 3.0', 'oauth2'], }, zip_safe = False, ) pywws-24.2.0/src/0000755000200200001440000000000014556655656013533 5ustar jimusers00000000000000pywws-24.2.0/src/contributors/0000755000200200001440000000000014556655656016270 5ustar jimusers00000000000000pywws-24.2.0/src/contributors/DCO.txt0000644000200200001440000000261613305436025017415 0ustar jimusers00000000000000Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 660 York Street, Suite 102, San Francisco, CA 94110 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. pywws-24.2.0/src/contributors/contributors.txt0000644000200200001440000000300014371663116021540 0ustar jimusers00000000000000Developers ---------- Jim Easterbrook jim@jim-easterbrook.me.uk x2q 3v1n0 Robin Kearney robin@kearney.co.uk Rod Persky Morten Høybye Frederiksen morten@mfd-consult.dk Simon Josefsson simon@josefsson.org Matthew Hilton matthilton2005@gmail.com Sabine Tobolka oe1yvw@gmail.com Markus Birth markus@birth-online.de Chris Ramsay chris@ramsay-family.net Christian Benke benkokakao@gmail.com Ian Wilkinson null@sgtwilko.f9.co.uk Tim Richardson tim@potton.me.uk Richard Truran ashenshugar@outlook.com Mark Jarvis jarvism@thisaddressdoesnotexist.co.uk Vladimir Michl vladimir.michl.vt@gmail.com David Bowen david@myforest.com Translators ----------- Edoardo edoardo69@hotmail.it Jacques Desroches metelsto@gmail.com Sunshades joacim@ahlstrand.info Johabu johabu96@yahoo.de karte2@gmail.com Kyle Gordon kyle@lodge.glasgownet.com> Πέτρος nouvakis@sch.gr Ramiro ramiro.sanchez@telefonica.net Rick Sulman rick@sulman.org Pyttsen weather@spacelab.se Tech2304 tech2304@gmail.com Pablo Vera pablo.vera82@gmail.com pywws-24.2.0/src/doc/0000755000200200001440000000000014556655656014300 5ustar jimusers00000000000000pywws-24.2.0/src/doc/api_index.rst0000644000200200001440000000444214023163712016746 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-20 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Python programs and modules =========================== Set up and configure pywws -------------------------- .. autosummary:: :toctree: api pywws.testweatherstation pywws.setweatherstation pywws.version pywws.reprocess pywws.usbtest pywws.mergeewdata Get data and process it ----------------------- .. autosummary:: :toctree: api pywws.hourly pywws.livelog pywws.livelogdaemon .. _api-index-services: Upload data to online "services" -------------------------------- .. autosummary:: :toctree: api pywws.service pywws.service.ftp pywws.service.sftp pywws.service.copy pywws.service.cwop pywws.service.metoffice pywws.service.mqtt pywws.service.openweathermap pywws.service.pwsweather pywws.service.temperaturnu pywws.service.underground pywws.service.weathercloud pywws.service.wetterarchivde pywws.service.windy pywws.service.twitter pywws.service.mastodon "Internal" modules ------------------ .. autosummary:: :toctree: api pywws.regulartasks pywws.logdata pywws.process pywws.calib pywws.plot pywws.windrose pywws.template pywws.forecast pywws.weatherstation pywws.device_libusb1 pywws.device_pyusb1 pywws.device_pyusb pywws.device_ctypes_hidapi pywws.device_cython_hidapi pywws.storage pywws.filedata pywws.sqlite3data pywws.timezone pywws.localisation pywws.conversions pywws.logger pywws.constants pywws-24.2.0/src/doc/conf.py0000644000200200001440000002204614556653422015570 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-20 pywws contributors # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # pywws documentation build configuration file, created by # sphinx-quickstart on Fri Sep 30 08:05:58 2011. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import os import sys from unittest.mock import Mock # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) ##sys.path.insert(0, os.path.abspath('..')) on_rtd = os.environ.get('READTHEDOCS', None) == 'True' # allow documentation to be compiled without installing dependencies for mod_name in ('hid', 'oauth2', 'mastodon', 'twitter', 'pytz', 'paho', 'paho.mqtt.client', 'paramiko', 'usb', 'usb.core', 'usb.util', 'libusb1', 'usb1', 'daemon.daemon', 'daemon.runner'): sys.modules[mod_name] = Mock() # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx', 'sphinx.ext.inheritance_diagram'] autosummary_generate = True autoclass_content = 'class' autodoc_member_order = 'bysource' autodoc_default_flags = ['members', 'undoc-members', 'show-inheritance'] intersphinx_mapping = { 'python': ('https://docs.python.org/2', None), } # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] highlight_language = 'none' rst_epilog = """ ---- Comments or questions? Please subscribe to the pywws mailing list http://groups.google.com/group/pywws and let us know. """ # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'pywws' copyright = u'2008-20, pywws contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. #version = # The full version, including alpha/beta/rc tags. #release = # read current version info without importing package with open('../pywws/__init__.py') as f: exec(f.read()) version = __version__ release = __version__ + '.dev' + _release # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None if not on_rtd and 'LANG' in os.environ: language = os.environ['LANG'].split('_')[0] locale_dirs = ['../pywws/lang'] # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False show_authors = True # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None html_logo = 'pywws_logo.png' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None html_favicon = 'pywws_logo.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True html_show_sourcelink = False # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'pywwsdoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'pywws.tex', u'pywws Documentation', u'Jim Easterbrook', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'pywws', u'pywws Documentation', [u'Jim Easterbrook'], 1) ] pywws-24.2.0/src/doc/copyright.rst0000644000200200001440000000213613305436032017014 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2015-18 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. pywws Contributors ================== The copywright to pywws and its documentation is jointly held by the following contributors. .. literalinclude:: ../contributors/contributors.txt .. _copyright-contributing: .. include:: ../../CONTRIBUTING.rst pywws-24.2.0/src/doc/essentials/0000755000200200001440000000000014556655656016452 5ustar jimusers00000000000000pywws-24.2.0/src/doc/essentials/CHANGELOG.rst0000644000200200001440000000167313305436026020455 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-13 Jim Easterbrook jim@jim-easterbrook.me.uk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Change Log ========== .. literalinclude:: ../../../CHANGELOG.txtpywws-24.2.0/src/doc/essentials/LICENCE.rst0000644000200200001440000000173113305436026020223 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-13 Jim Easterbrook jim@jim-easterbrook.me.uk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. GNU General Public License ========================== .. literalinclude:: ../../../LICENCE.txtpywws-24.2.0/src/doc/essentials/dependencies.rst0000644000200200001440000002125714023163712021611 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-20 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Dependencies ============ The list of other software that pywws depends on looks frighteningly long at first glance. However, many of these packages won't be needed by most users. What you need depends on what you want to do with pywws. Remember, it's a "kit of parts" rather than a monolithic application. Some of the requirements are Python packages that can be downloaded from the `Python Package Index (PyPI) `_. I recommend using `pip `_ to install these. You should be able to install the remaining dependencies using your operating system's package manager. This is a lot easier than downloading and compiling source files from the project websites. Note that some Linux distributions use different names for some of the packages, e.g. in Ubuntu, pyusb is called python-usb. Note: some of these libraries may have their own dependencies that you may need to install. Follow the links to read more about each library's requirements. Essential --------- * `Python `_ version 2.7 or higher, preferably Python 3 If you are stuck on Python 2.5 or 2.6 for some reason you can use the older `"legacy" branch `_ of pywws. This will not be further developed so you'll be missing out on any improvements made to the main branch. * `pip `_ You will probably be able to install pip with your system's package manager, where it may be called python-pip or python3-pip or something similar. If not, download and run the ``get-pip.py`` file from the pip web site. In either case you should immediately use pip to install the latest version of itself:: sudo pip install --upgrade pip Make sure you install the correct Python version's pip. If you want to install pywws for both Python 2 and Python 3 you will need pip2 and pip3. * `tzlocal `_ This is a handy little module that provides information on your local time zone. It's best installed with ``pip``:: sudo pip install tzlocal .. _dependencies-usb: USB library ^^^^^^^^^^^ To retrieve data from a weather station pywws needs a python library that allows it to communicate via USB. There is a variety of USB libraries that can be used. Not all of them are available on all computing platforms, which may restrict your choice. Mac OS X """""""" On MacOS X the operating system's generic hid driver "claims" the weather station, which makes it very difficult to use any other USB interface. Unfortunately, you will need to download and compile hidapi yourself. * `hidapi `_ * `ctypes `_ (your package manager may know it as python-ctypes) If you can't install ctypes then you can try the Cython interface to hidapi instead: * `cython-hidapi `_ * `cython `_ (your package manager may know it as python-Cython) Other systems """"""""""""" Other systems use a Python interface to the libusb system library. There is a choice of interface and library version - install the latest that is available for your computer. * `libusb `_ version 1.x (should be available from the package manager) * `python-libusb1 `_ version 1.3+ :: pip install libusb1 **or** * `libusb `_ version 1.x or version 0.1 (should be available from the package manager) * `PyUSB `_ version 1.0+ :: pip install pyusb If neither of these options works for you then you may be able to use hidapi -- see the Mac OS X instructions above. .. versionchanged:: 15.01.0.dev1265 added ability to use python-libusb1 interface. Flexible timed tasks -------------------- The :py:mod:`pywws.regulartasks` module can do tasks at particular times and/or dates. This requires the croniter library. (Simple hourly, daily or 'live' tasks don't need this library.) * `croniter `_ :: pip install croniter Running as a daemon ------------------- The :py:mod:`pywws.livelogdaemon` module runs pywws live logging as a proper UNIX daemon process. It requires the python-daemon library: * `python-daemon `_ :: pip install python-daemon Graph drawing ------------- The :py:mod:`pywws.plot` module uses gnuplot to draw graphs. If you want to produce graphs of weather data, e.g. to include in a web page, you need to install the gnuplot application: * `gnuplot `_ v4.2 or higher (should be available from the package manager) After installing gnuplot you should edit weather.ini (see :doc:`../guides/weather_ini`) and set the ``gnuplot version`` config item. Finding out the installed gnuplot version is easy:: gnuplot -V Weather "service" uploading --------------------------- Uploading to HTTP based "services" such as Weather Underground requires the Python requests library: * `requests `_ :: pip install requests Secure website uploading (sftp) ------------------------------- The :py:mod:`pywws.towebsite` module can use "ftp over ssh" (sftp) to upload files to your web-site. Normal uploading just uses Python's standard modules, but if you want to use sftp you need to install these two modules: * `paramiko `_ * `pycrypto `_ :: sudo pip install pycrypto paramiko .. _dependencies-twitter: Twitter updates --------------- The :py:mod:`pywws.service.twitter` module can be used to send weather status messages to Twitter. Posting to Twitter requires these modules: * `python-twitter `_ v3.0 or higher * `python-oauth2 `_ :: sudo pip install python-twitter oauth2 **or** * `tweepy `_ v2.0 or higher * `python-oauth2 `_ :: sudo pip install tweepy oauth2 Note that ``tweepy`` appears to be the less reliable of the two. If you have problems, e.g. with character encoding, try installing ``python-twitter`` instead. .. _dependencies-mqtt: MQTT ---- .. versionadded:: 14.12.0.dev1260 The :py:mod:`pywws.service.mqtt` module can be used to send weather data to an MQTT broker. This requires the paho-mqtt module: * `paho-mqtt `_ :: sudo pip install paho-mqtt .. _dependencies-translations: To create new language translations ----------------------------------- pywws can be configured to use languages other than English, as described in :doc:`../guides/language`. The Babel package is required to extract the strings to be translated and to compile the translation files. * `babel `_ :: sudo pip install babel Copying files to or from Transifex requires the transifex-client package. * `transifex-client `_ :: sudo pip install transifex Translating the documentation using local files needs the sphinx-intl package. * `sphinx-intl `_ :: sudo pip install sphinx-intl .. versionchanged:: 14.05.dev1209 pywws previously used the gettext package. .. _dependencies-compile-documentation: To 'compile' the documentation ------------------------------ The documentation of pywws is written in "ReStructured text". A program called Sphinx is used to convert this easy to write format into HTML for use with a web browser. If you'd like to create a local copy of the documentation (so you don't have to rely on the online version, or to test a translation you're working on) you need to install Sphinx, version 1.3 or later. * `Sphinx `_ :: sudo pip install sphinx pywws-24.2.0/src/doc/guides/0000755000200200001440000000000014556655656015560 5ustar jimusers00000000000000pywws-24.2.0/src/doc/guides/getstarted.rst0000644000200200001440000004041113351134756020441 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-18 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. How to get started with pywws ============================= Installation ------------ First of all you need to install Python and a USB library (to allow Python to access the weather station). See :doc:`../essentials/dependencies` for more detail. Create a directory for all your weather related files and change to it. For example (on a Linux or similar operating system):: mkdir ~/weather cd ~/weather Easy installation ^^^^^^^^^^^^^^^^^ The easiest way to install pywws is with the pip command:: sudo pip install pywws Upgrading pywws is also a one line command:: sudo pip install -U pywws Now you are ready to :ref:`test-weather-station`. .. _getstarted-download: Download and extract ^^^^^^^^^^^^^^^^^^^^ If you prefer not to use pip, or you want easy access to the pywws source files (e.g. to translate the documentation -- see :doc:`language`), you can download and extract the files into your weather directory. Visit https://pypi.org/project/pywws/ and download one of the .tar.gz files. Put it in your weather directory, then extract all the files, for example:: cd ~/weather tar xf pywws-18.4.1.tar.gz This should create a directory (called ``pywws-18.4.1`` in this example) containing all the pywws source files. It is convenient to create a soft link to this awkwardly named directory:: cd ~/weather ln -s pywws-18.4.1 pywws Upgrading a downloaded snapshot is the same process as the first installation. Download the .tar.gz file, extract its contents, then delete the soft link pointing to the old download and create one pointing to the new download. Once you are satisfied the new version is working OK you can delete the old download entirely. Clone the repository ^^^^^^^^^^^^^^^^^^^^ The PyPI files contain a snapshot release of the software - a new one is issued every few months. If you want to use the very latest version of pywws, e.g. to work on fixing a bug, you can get all the files you need from the `GitHub repository `_. Install git and use it to clone the repos:: cd ~/weather git clone https://github.com/jim-easterbrook/pywws.git To upgrade you use git to pull any changes:: cd ~/weather/pywws git pull Install pywws ^^^^^^^^^^^^^ If you have downloaded or cloned the pywws source files, you need to use setup.py to install it:: cd ~/weather/pywws python setup.py compile_catalog python setup.py build sudo python setup.py install The ``python setup.py compile_catalog`` step is only needed if you want to use pywws in a language other than English. See :ref:`test-translation` for more detail. Compile documentation (optional) -------------------------------- If you'd like to have a local copy of the pywws documentation (and have downloaded the source or cloned the repo) you can "compile" the English documentation. This requires the sphinx package:: cd ~/weather/pywws python -B setup.py build_sphinx To compile the documentation in another language you need to set the ``LANG`` environment variable. For example, to compile the French documentation:: cd ~/weather/pywws LANG=fr python -B setup.py build_sphinx The compiled documentation should then be found at ``~/weather/pywws/doc/html/index.html``. See :doc:`language` for more detail. .. _test-weather-station: Test the weather station connection ----------------------------------- Now you're ready to test your pywws installation. Connect the weather station (if not already connected) then run the :py:mod:`pywws.testweatherstation` module:: pywws-testweatherstation If everything is working correctly, this should dump a load of numbers to the screen, for example:: 0000 55 aa ff ff ff ff ff ff ff ff ff ff ff ff ff ff 05 20 01 51 11 00 00 00 81 00 00 0f 00 00 60 55 0020 ea 27 a0 27 00 00 00 00 00 00 00 10 10 12 13 45 41 23 c8 00 32 80 47 2d 2c 01 2c 81 5e 01 1e 80 0040 96 00 c8 80 a0 28 80 25 a0 28 80 25 03 36 00 05 6b 00 00 0a 00 f4 01 18 03 00 00 00 00 00 00 00 0060 00 00 4e 1c 63 0d 2f 01 73 00 7a 01 47 80 7a 01 47 80 e4 00 00 00 71 28 7f 25 bb 28 bd 25 eb 00 0080 0c 02 84 00 0e 01 e3 01 ab 03 dc 17 00 10 08 21 08 54 10 03 07 22 18 10 08 11 08 30 10 04 21 16 00a0 26 08 07 24 17 17 08 11 01 06 10 09 06 30 14 29 09 01 06 07 46 09 06 30 14 29 09 01 06 07 46 08 00c0 08 31 14 30 10 05 14 15 27 10 01 26 20 47 09 01 23 05 13 10 01 26 20 47 09 01 23 05 13 10 02 22 00e0 11 06 10 02 22 11 06 08 07 07 19 32 08 12 13 22 32 08 09 07 08 48 01 12 05 04 43 10 02 22 14 43 There are several reasons why this might not work. Most likely is a 'permissions' problem. This can be tested by running the command as root:: sudo pywws-testweatherstation If this works then you may be able to allow your normal user account to access the weather station by setting up a `'udev' `_ rule. The exact method may depend on your Linux version, but this is typically done by creating a file ``/etc/udev/rules.d/39-weather-station.rules`` containing the following:: ACTION!="add|change", GOTO="weatherstation_end" SUBSYSTEM=="usb", ATTRS{idVendor}=="1941", ATTRS{idProduct}=="8021", GROUP="weatherstation" LABEL="weatherstation_end" Unplug and replug the station's USB connection to force ``udev`` to apply the new rule. This allows any user in the group ``weatherstation`` to access the weather station. You need to create this group and add your normal user account to it -- many Linux systems have a GUI for user and group management. If you have any other problem, please ask for help on the pywws mailing list: http://groups.google.com/group/pywws Decoding the numbers ^^^^^^^^^^^^^^^^^^^^ The ``pywws-testweatherstation`` command has options to decode the numbers shown above, or to show you the station's logged data. The ``--help`` option prints a usage message:: jim@firefly ~/weather/pywws $ pywws-testweatherstation --help Test connection to weather station. usage: /usr/bin/pywws-testweatherstation [options] options are: --help display this help -c | --change display any changes in "fixed block" data -d | --decode display meaningful values instead of raw data -h n | --history n display the last "n" readings -l | --live display 'live' data -m | --logged display 'logged' data -u | --unknown display unknown fixed block values -v | --verbose increase amount of reassuring messages (repeat for even more messages e.g. -vvv) jim@firefly ~/weather/pywws $ Using the ``--decode`` option shows the decoded "fixed block" data:: jim@firefly ~/weather/pywws $ pywws-testweatherstation -d 10:02:16:pywws.logger:pywws version 18.4.2, build 1523 (092cf26) {'abs_pressure': 1001.6, 'alarm': {'abs_pressure': {'hi': 1040, 'lo': 960}, 'dewpoint': {'hi': 10, 'lo': -10}, 'hum_in': {'hi': 65, 'lo': 35}, 'hum_out': {'hi': 70, 'lo': 45}, 'illuminance': 0, 'rain': {'day': 150, 'hour': 3}, 'rel_pressure': {'hi': 1040, 'lo': 960}, 'temp_in': {'hi': 20, 'lo': 0}, 'temp_out': {'hi': 30, 'lo': -10}, 'time': '12:00', 'uv': 0, 'wind_ave': {'bft': 0, 'ms': 11.2}, 'wind_dir': 0, 'wind_gust': {'bft': 0, 'ms': 22.3}, 'windchill': {'hi': 20, 'lo': 0}}, ... 'read_period': 5, 'rel_pressure': 987.2, 'settings_1': {'bit3': False, 'bit4': False, 'pressure_hPa': True, 'pressure_inHg': False, 'pressure_mmHg': False, 'rain_in': False, 'temp_in_F': False, 'temp_out_F': False}, 'settings_2': {'bit5': False, 'bit6': False, 'bit7': False, 'wind_bft': False, 'wind_kmph': False, 'wind_knot': False, 'wind_mph': True, 'wind_mps': False}, 'timezone': -1, 'unknown_01': 0, 'unknown_18': 0} jim@firefly ~/weather/pywws $ The ``--history`` option shows recent "logged" data, starting with the current "live" record:: jim@firefly ~/weather/pywws $ pywws-testweatherstation -d -h 2 10:06:28:pywws.logger:pywws version 18.4.2, build 1523 (092cf26) ... Recent history 0x30a0 2018-04-27 10:06:00 {'abs_pressure': 1001.5, 'delay': 2, 'hum_in': 48, 'hum_out': 88, 'rain': 2178.6, 'status': {'rain_overflow': False, 'lost_connection': False}, 'temp_in': 18.4, 'temp_out': 8.5, 'wind_ave': 0.7, 'wind_dir': 5, 'wind_gust': 1} 0x3090 2018-04-27 10:04:00 {'abs_pressure': 1001.6, 'delay': 5, 'hum_in': 47, 'hum_out': 88, 'rain': 2178.6, 'status': {'rain_overflow': False, 'lost_connection': False}, 'temp_in': 18.4, 'temp_out': 8.5, 'wind_ave': 1.7, 'wind_dir': 6, 'wind_gust': 3.4} jim@firefly ~/weather/pywws $ These options are useful if you ever need to examine the raw data as stored by the station, before pywws does any processing. Set up your weather station --------------------------- If you haven't already done so, you should set your weather station to display the correct relative atmospheric pressure. (See the manual for details of how to do this.) pywws gets the offset between relative and absolute pressure from the station, so this should be set before using pywws. You can get the correct relative pressure from your location by looking on the internet for weather reports from a nearby station, ideally an official one such as an airport. This is best done during calm weather when the pressure is almost constant over a large area. Set the weather station logging interval ---------------------------------------- Your weather station probably left the factory with a 30 minute logging interval. This enables the station to store about 11 weeks of data. Most pywws users set up their computers to read data from the station every hour, or more often, and only need the station to store enough data to cover computer failures. The recommended interval is 5 minutes, which still allows 2 weeks of storage. Use :py:mod:`pywws.setweatherstation` to set the interval:: pywws-setweatherstation -r 5 Note that the weather station will not start using the new interval until the current 30 minute logging period is finished. This may cause "station is not logging data" errors when running pywws logging. If this happens you need to wait until the 30 minute logging period ends. Log your weather station data ----------------------------- First, choose a directory to store all your weather station data. This will be written to quite frequently, so a disk drive is preferable to a flash memory stick or card, as these have a limited number of writes. In most cases your home directory is suitable, for example:: mkdir ~/weather/data This directory is referred to elsewhere in the pywws documentation as your data directory. Make sure your computer has the right date & time, and time zone, as these are used to label the weather station data. If you haven't already done so, it's worth setting up NTP to synchronise your computer to a 'time server'. The first time you run :py:mod:`pywws.logdata` it will create a configuration file in your data directory called 'weather.ini' and then stop. You need to edit the configuration file and change the line ``ws type = Unknown`` to ``ws type = 1080`` or ``ws type = 3080``. (If your weather station console displays solar illuminance you have a 3080 type, all others are 1080.) Then run :py:mod:`pywws.logdata` again. This may take several minutes, as it will copy all the data stored in your station's memory. The :py:mod:`pywws.logdata` program has a 'verbose' option that increases the amount of messages it displays while running. This is useful when running it manually, for example:: python -m pywws.logdata -vvv ~/weather/data (Replace ``~/weather/data`` with your data directory, if it's different.) You should now have some data files you can look at. For example:: more ~/weather/data/raw/2012/2012-12/2012-12-16.txt (Replace the year, month and day with ones that you have data for.) Convert old EasyWeather data (optional) --------------------------------------- If you had been running EasyWeather before deciding to use pywws, you can convert the data EasyWeather had logged to the pywws format. Find your EasyWeather.dat file and then convert it:: python -m pywws.mergeewdata EasyWeather.dat ~/weather/data (Recent versions of EasyWeather may use a different file format which :py:mod:`pywws.mergeewdata` cannot handle.) Set some configuration options ------------------------------ After running :py:mod:`pywws.logdata` there should be a configuration file in your data directory called 'weather.ini'. Open this with a text editor. You should find something like the following:: [paths] work = /tmp/pywws [config] usb activity margin = 3.0 ws type = 1080 pressure offset = 9.3 logdata sync = 1 (Don't worry about the order of items within each section. Re-ordering them has no effect.) You need to add a new entry in the ``[config]`` section called ``day end hour``. This tells pywws what convention you want to use when calculating daily summary data. The entry should have two values separated by a comma: a number in the range 0 to 23 (the hour of day, in local winter time) and a single word ``True`` or ``False`` to say if the day end should adjust with summer (daylight savings) time. In the UK, the 'meteorological day' is usually from 09:00 to 09:00 GMT (10:00 to 10:00 BST during summer), so I use a day end hour value of ``9, False``. If you prefer to use midnight, winter or summer, you should use ``0, True``. After editing, your weather.ini file should look something like this:: [paths] work = /tmp/pywws [config] usb activity margin = 3.0 ws type = 1080 pressure offset = 9.3 logdata sync = 1 day end hour = 9, False You can also edit the ``pressure offset`` value to adjust how pywws calculates the relative (sea level) air pressure from the absolute value that the station measures. If you change the pressure offset or day end hour in future, you must update all your stored data by running :py:mod:`pywws.reprocess`. For more detail on the configuration file options, see :doc:`../guides/weather_ini`. .. versionchanged:: 13.10_r1082 made ``pressure offset`` a config item. Previously it was always read from the weather station. Process the raw data -------------------- :py:mod:`pywws.logdata` just copies the raw data from the weather station. To do something useful with that data you probably need hourly, daily and monthly summaries. These are created by :py:mod:`pywws.process`. For example:: python -m pywws.process ~/weather/data You should now have some processed files to look at:: more ~/weather/data/daily/2012/2012-12-16.txt If you ever change your ``day end hour`` or ``pressure offset`` configuration settings, you will need to reprocess all your weather data. You can do this by running :py:mod:`pywws.reprocess`:: python -m pywws.reprocess ~/weather/data You are now ready to set up regular or continuous logging, as described in :doc:`hourlylogging` or :doc:`livelogging`. Read the documentation ---------------------- You're looking at it right now! The :doc:`index` section is probably the most useful bit to read first, but the :doc:`../api_index` section has a lot more detail on the various pywws modules and commands. pywws-24.2.0/src/doc/guides/hourlylogging.rst0000644000200200001440000001571213351134756021172 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-18 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. How to set up 'hourly' logging with pywws ========================================= Introduction ------------ There are two quite different modes of operation with pywws. Traditionally :py:mod:`pywws.hourly` would be run at regular intervals (usually an hour) from cron. This is suitable for fairly static websites, but more frequent updates can be useful for sites such as Weather Underground (http://www.wunderground.com/). The newer :py:mod:`pywws.livelog` program runs continuously and can upload data every 48 seconds. Note that although this document (and the program name) refers to 'hourly' logging, you can run :py:mod:`pywws.hourly` as often or as infrequently as you like, but don't try to run it more often than double your logging interval. For example, if your logging interval is 10 minutes, don't run :py:mod:`pywws.hourly` more often than every 20 minutes. Getting started --------------- First of all, you need to install pywws and make sure it can get data from your weather station. See :doc:`getstarted` for details. Try running :py:mod:`pywws.hourly` from the command line, with a high level of verbosity so you can see what's happening. Use the ``pywws-hourly`` command to run :py:mod:`pywws.hourly`:: pywws-hourly -vvv ~/weather/data (As usual, replace ``~/weather/data`` with your weather data directory.) Within five minutes (assuming you have set a 5 minute logging interval) you should see a 'live_data new ptr' message, followed by fetching any new data from the weather station and processing it. .. versionchanged:: 14.04.dev1194 the ``pywws-hourly`` command replaced ``scripts/pywws-hourly.py``. Configuring file locations -------------------------- Open your weather.ini file with a text editor. You should have a ``[paths]`` section similar to the following (where ``xxx`` is your user name):: [paths] work = /tmp/pywws templates = /home/xxx/weather/templates/ graph_templates = /home/xxx/weather/graph_templates/ modules = /home/xxx/weather/modules/ Edit these to suit your installation and preferences. ``work`` is a temporary directory used to store intermediate files. If your computer uses solid state storage, such as a Raspberry Pi's SD card, it's a good idea to make this a "RAM disk" to reduce storage "wear". ``templates`` is the directory where you keep your text template files, ``graph_templates`` is the directory where you keep your graph template files, and ``modules`` is a directory for any extra modules you write. Don't use the pywws example directories for your templates, as they will get over-written when you upgrade pywws. Copy your text and graph templates to the appropriate directories. You may find some of the examples provided with pywws useful to get started. The ``pywws-version -v`` command should show you where the examples are on your computer. .. versionadded:: 14.04.dev1194 the ``pywws-version`` command. Configuring periodic tasks -------------------------- In weather.ini you should have ``[live]``, ``[logged]``, ``[hourly]``, ``[12 hourly]``, and ``[daily]`` sections similar to the following:: [logged] services = [] text = [] plot = [] [hourly] ... These specify what :py:mod:`pywws.hourly` should do when it is run. Tasks in the ``[live]`` and ``[logged]`` sections are done when there is new logged data, tasks in the ``[hourly]`` section are done every hour, tasks in the ``[12 hourly]`` section are done twice daily and tasks in the ``[daily]`` section are done once per day. The ``plot`` and ``text`` entries are lists of template files for plots and text files to be processed. The ``services`` entry is a list of online weather services to upload data and files to, e.g. ``'underground'`` or ``('ftp', '24hrs.txt')``. Add the names of your template files and weather services to the appropriate entries, for example:: [logged] services = ['underground', 'metoffice'] plot = [] text = [] [hourly] services = [('twitter', 'tweet.txt'), ('ftp', '7days.png', '24hrs.png', 'rose_24hrs.png', '24hrs.txt', '6hrs.txt', '7days.txt')] plot = ['7days.png.xml', '24hrs.png.xml', 'rose_24hrs.png.xml'] text = ['tweet.txt', '24hrs.txt', '6hrs.txt', '7days.txt'] [12 hourly] services = [] plot = [] text = [] [daily] services = [('twitter', 'forecast.txt'), ('ftp', '28days.png', 'allmonths.txt')] plot = ['28days.png.xml'] text = ['forecast.txt', 'allmonths.txt'] Note that the ``twitter`` and ``ftp`` "services" use files generated by the ``plot`` and ``text`` items. It's probably best not to add all of these at once. You could start by uploading one file to your web site, then when that's working add the remaining web site files. You can add Twitter and other services later on. You can test that things are working by removing the ``[last update]`` section from status.ini, then running :py:mod:`pywws.hourly` again:: pywws-hourly -v ~/weather/data .. versionadded:: 14.05.dev1211 ``[cron name]`` sections. If you need more flexibility in when tasks are done you can use ``[cron name]`` sections. See :doc:`weather_ini` for more detail. Run as a cron job ----------------- Most UNIX/Linux systems have a 'cron' daemon that can run programs at certain times, even if you are not logged in to the computer. You edit a 'crontab' file to specify what to run and when to run it. For example, to run :py:mod:`pywws.hourly` every hour, at zero minutes past the hour:: 0 * * * * pywws-hourly /home/xxx/weather/data This might work, but if it didn't you probably won't get any error messages to tell you what went wrong. It's much better to run a script that runs :py:mod:`pywws.hourly` and then emails you any output it produces. Here's a script I've used:: #!/bin/sh # # weather station logger calling script export PATH=$PATH:/usr/local/bin if [ ! -d /home/jim/weather/data/ ]; then exit fi log=/var/log/log-weather pywws-hourly -v /home/jim/weather/data >$log 2>&1 # mail the log file /home/jim/scripts/email-log.sh $log "weather log" You’ll need to edit this quite a lot to suit your file locations and so on, but it gives some idea of what to do. pywws-24.2.0/src/doc/guides/humidex.rst0000644000200200001440000001334714221250641017733 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-13 Jim Easterbrook jim@jim-easterbrook.me.uk This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Humidity Index (Humidex) ======================== .. sectionauthor:: Rodney Persky Background ---------- Using your weather station can be fun, and reporting daily to various weather data sites can be very useful for your neighbours to check out the weather. However, at some point you may want to know how the weather effects your body, and if there is a way to tell when it's good or not to work outdoors. Here enters a whole realm of calculations based on energy transferring though walls, and the resistance offered by them. It can be a great learning adventure, and can save you a great deal of money, finding out how energy moves around. Introduction ------------ Humidex is a tool to determine how an individuals body will react to the combination of Wind, Humidity and Temperature. The background of which is a heat balance across from your midriff to your skin, and is complimentary to ISO 7243 "Hot Environments - Estimation of the heat stress on working man". A few important notes, * These indices are based off a number of assumptions which may result in over or under-estimation of your bodies internal state * A personal weather station may not show the correct conditions, and may have an over or under estimation of the humidity, wind or temperature * Clothing choices effect the personal fatigue and the bodies ability to reject heat, a low Humidity Index doesn't mean you can wear anything * An individuals fitness will effect their bodies response to changing temperature, and experience will aid in knowing when to stop working * The duration of activities that can be performed requires knowledge on the intensity, which cannot be represented though this index Assumptions ----------- There are a number of assumptions that have been made to make this work which will directly affect its usability. These assumptions however have not been made available from Environment Canada, who are the original developers of the Humidex used in the PYWWS function cadhumidex. It is safe enough however to say that the following would have been some assumptions: * Clothing type, thickness * Skin area exposed to free air * Sun exposure However, there are a number of assumptions pywws needs to make in calculating the Humidex: * The humidity, wind and temperature readings are correct There are also assumptions about the individuals body type and 'acclimatisation' * An individuals fitness will effect their bodies response to changing temperature * Experience will aid in knowing when to stop working Important References -------------------- Being Prepared for Summer - http://www.ec.gc.ca/meteo-weather/default.asp?lang=En&n=86C0425B-1 How to use ---------- The function is descriptively named ``cadhumidex`` and has the parameters temperature and humidity, essentially the function operates as a conversion and can be used in a straightforward manner:: cadhumidex(data['temp_out'],data['hum_out']) Putting it together, I have added colours that follow basic warning colors and the different brackets to produce a decent graph:: Humidity Index, Bands indicate apparent discomfort in standard on-site working conditions 1820, 1024 hours=48 2 %H%M 29, 55 29, 55 Humidex raw Humidex cadhumidex(data['temp_out'],data['hum_out']) 4 x1y2 HI > 54, Heat Stroke Probable 54 x1y2 1 HI > 45, Dangerous 45 x1y2 8 HI > 40, Intense 40 x1y2 6 HI > 35, Evident 35 x1y2 2 HI > 30, Noticeable 30 x1y2 3 Not running the latest update? ------------------------------ If you are not running the latest update / do not want to, then this can be implemented using a longer as follows:: data['temp_out']+0.555*(6.112*10**(7.5*data['temp_out']/(237.7+data['temp_out']))*data['hum_out']/100-10) pywws-24.2.0/src/doc/guides/index.rst0000644000200200001440000000202613351134756017402 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-18 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. User guides =========== Contents: .. toctree:: :maxdepth: 3 getstarted hourlylogging livelogging integration language weather_ini logfiles humidex pywws-24.2.0/src/doc/guides/integration.rst0000644000200200001440000001406413612332477020623 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-20 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. How to integrate pywws with various weather services ==================================================== This guide gives brief instructions on how to use pywws with some other weather services and software. It is not comprehensive, and most services are covered in more detail elsewhere. YoWindow -------- `YoWindow `_ is a weather display widget that can display data from an internet source, or from your weather station. To display data from your station pywws needs to write to a local file, typically every 48 seconds when new data is received. This is easy to do: #. Stop all pywws software #. Copy the ``yowindow.xml`` example template to your text template directory. #. Add the yowindow template to the ``[live]`` tasks in ``weather.ini``:: [live] text = ['yowindow.xml'] #. Restart pywws live logging. This will write the file to the ``output`` subdirectory of the ``work`` directory set in :ref:`weather.ini `. If you prefer to store the file somewhere else you can use the :py:mod:`pywws.service.copy` service to copy it there. For example:: [copy] directory = /home/heavyweather/ [live] text = ['yowindow.xml'] services = [('copy', 'yowindow.xml')] You can check the file is being updated every 48 seconds by using ``more`` or ``cat`` to dump it to the screen. Finally configure yowindow to use this file. See ``_ for instructions on how to do this. .. _guides-integration-other: Other "services" ---------------- The remaining weather service uploads are handled by modules in the :ref:`pywws.service ` sub-package. .. autosummary:: pywws.service.ftp pywws.service.sftp pywws.service.copy pywws.service.cwop pywws.service.metoffice pywws.service.mqtt pywws.service.openweathermap pywws.service.pwsweather pywws.service.temperaturnu pywws.service.underground pywws.service.weathercloud pywws.service.wetterarchivde pywws.service.windy pywws.service.twitter pywws.service.mastodon These each use a separate thread to upload the data so that a slow or not responding service doesn't delay other processing or uploads. The service uploaders are all used in a similar fashion: #. Create an account with the service. #. Stop all pywws software. #. Run the service module directly to initialise its entry in ``weather.ini``. For example:: python -m pywws.service.underground /home/jim/weather/data #. Edit ``weather.ini`` and add your account details to the appropriate section (e.g. ``[underground]``). #. Run the service module directly (with high verbosity) to make sure your account details are correct:: python -m pywws.service.underground -vvv /home/jim/weather/data Each service's server software responds differently to correct or incorrect uploads. You should be able to tell from the response if it was successful or not. #. Edit ``weather.ini`` and add the service to the ``[logged]`` (and optionally ``[live]``) sections, e.g.:: [logged] services = ['underground'] [live] services = ['underground'] Note that some services, such as :py:mod:`pywws.service.copy`, need one or more parameters. Instead of a single word entry, such as ``underground``, these use a bracketed list, for example ``('copy', 'yowindow.xml')``. #. Restart pywws live logging. Some of the services are more complicated to configure. More detailed instructions are given in the module's documentation. Follow the links in the table above. Many of the services will upload the last seven days of data (referred to as "catchup" mode) when first run. This may take an hour or more, but the use of separate threads means this doesn't adversely affect the rest of pywws. Writing your own uploader ------------------------- If you'd like to send data to a service which is not (yet) included in pywws you can write your own uploader module and put it in your ``modules`` directory. You should start by copying one of the existing modules from ``pywws.service``. Choose one with an API most like the service you want to upload to. Give the module a one word lowercase name that will be used as the uploader service name. Testing the module is a little different from before:: python ~/weather/modules/myservice.py -vvv ~/weather/data where ``~/weather/modules/myservice.py`` is the full path of your new module. Note what sort of response you get from the server. Some servers, such as Weather Underground, send a single word ``'success'`` response to indicate success, and a longer string indicating the cause of any failure. Other servers use HTTP response codes to indicate failure. Your module's ``upload_data`` method must return a ``(bool, str)`` tuple where the ``bool`` value indicates success (if ``True``) and the ``str`` value contains any message from the server. (If the server returns no message this string should be set to ``'OK'``.) Under normal operation pywws will log this message whenever it changes. Once your uploader is working you could contribute it to pywws if it's likely to be useful to other people. Don't forget to document it fully, then either send it to Jim or create a GitHub pull request. See :ref:`copyright-contributing` for instructions on doing this. pywws-24.2.0/src/doc/guides/language.rst0000644000200200001440000002126713305436032020055 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-18 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. How to use pywws in another language ==================================== Introduction ------------ Some parts of pywws can be configured to use your local language instead of British English. This requires an appropriate language file which contains translations of the various strings used in pywws. The pywws project relies on users to provide these translations. The pywws documentation can also be translated into other languages. This is a lot more work, but could be very useful to potential users who do not read English very well. Using existing language files ----------------------------- Program strings ^^^^^^^^^^^^^^^ There may already be a pywws translation for your preferred language. First you need to choose the appropriate two-letter code from the list at http://www.w3schools.com/tags/ref_language_codes.asp. For example, ``fr`` is the code for French. Now use the :py:mod:`pywws.localisation` module to do a quick test:: python -m pywws.localisation -t fr This should produce output something like this:: Locale changed from (None, None) to ('fr_FR', 'UTF-8') Translation set OK Locale decimal point: 23,2 date & time: lundi, 17 décembre (17/12/2012 16:00:48) Translations 'NNW' => 'NNO' 'rising very rapidly' => 'en hausse très rapide' 'Rain at times, very unsettled' => 'Quelques précipitations, très perturbé' This shows that pywws is already able to generate French output, and that your installation is correctly configured. Now you can edit the ``language`` entry in your :ref:`weather.ini ` file to use your language code. If the above test shows no translations into your language then you need to create a new language file, as described below. Text encodings ^^^^^^^^^^^^^^ The pywws default text encoding is ISO-8859-1, also known as Latin-1. This is suitable for several western European languages but not for some others. If you encounter problems you may need to use a different encoding. See the documentation of :py:mod:`pywws.template` and :py:mod:`pywws.plot` for more details. Documentation ^^^^^^^^^^^^^ If you have downloaded the pywws source files, or cloned the GitHub repository (see :ref:`how to get started with pywws `), you can compile a non-English copy of the documentation. This requires the `Sphinx `_ package, see :ref:`dependencies `. First delete the old documentation (if it exists) and then recompile using your language:: cd ~/weather/pywws rm -rf doc LANG=fr python -B setup.py build_sphinx Note that the ``build_sphinx`` command doesn't have a ``--locale`` (or ``-l``) option, so the language is set by a temporary environment variable. You can view the translated documentation by using a web browser to read the file ``~/weather/pywws/doc/html/index.html``. Writing new language files -------------------------- There are two ways to write new language files (or update existing ones) -- use the `Transifex `_ online system or use local files. Transifex is preferred as it allows several people to work on the same language, and makes your work instantly available to others. To test your translation you will need to have downloaded the pywws source files, or cloned the GitHub repository (see :ref:`how to get started with pywws `). You will also need to install the ``Babel`` package, see :ref:`dependencies `. .. _using-transifex: Using Transifex ^^^^^^^^^^^^^^^ If you'd like to use Transifex, please go to the `pywws Transifex project `_, click on "help translate pywws" and create a free account. Visit the pywws project page on Transifex and click on your language, then click on the "resource" you want to translate. (``pywws`` contains the program strings used when running pywws, the others contain strings from the pywws documentation.) This opens a dialog where you can choose to translate the strings online. Please read :ref:`translator-notes` before you start. When you have finished translating you should use the ``transifex-client`` program (see :ref:`dependencies `) to download files for testing. For example, this command downloads any updated files for the French language:: cd ~/weather/pywws tx pull -l fr Now you are ready to :ref:`test-translation`. Using local files ^^^^^^^^^^^^^^^^^ If you prefer not to use the Transifex web site you can edit language files on your own computer. This is done in two stages, as follows. Extract source strings """""""""""""""""""""" Program messages are extracted using the ``Babel`` package:: cd ~/weather/pywws mkdir -p build/gettext python -B setup.py extract_messages This creates the file ``build/gettext/pywws.pot``. This is a "portable object template" file that contains the English language strings to be translated. The documentation strings are extracted using the ``Sphinx`` package:: cd ~/weather/pywws python -B setup.py extract_messages_doc This creates several ``.pot`` files in the ``build/gettext/`` directory. Create language files """"""""""""""""""""" The ``sphinx-intl`` command is used to convert the ``.pot`` files to language specific ``.po`` files:: cd ~/weather/pywws sphinx-intl update --locale-dir src/pywws/lang -p build/gettext -l fr Now you can open the ``.po`` files in ``src/pywws/lang/fr/LC_MESSAGES/`` with your favourite text editor and start filling in the empty ``msgstr`` strings with your translation of the corresponding ``msgid`` string. Please read :ref:`translator-notes` before you start. .. _test-translation: Test the pywws translations --------------------------- The ``Babel`` package is used to compile program strings:: python -B setup.py compile_catalog --locale fr (Replace ``fr`` with the code for the language you are testing.) After compilation you can test the translation:: python setup.py build sudo python setup.py install python -m pywws.Localisation -t fr ``Sphinx`` is used to build the translated documentation:: cd ~/weather/pywws rm -rf doc LANG=fr python -B setup.py build_sphinx You can view the translated documentation by using a web browser to read the file ``~/weather/pywws/doc/html/index.html``. .. _translator-notes: Notes for translators --------------------- The pywws program strings (``pywws.po``) are quite simple. They comprise simple weather forecasts ("Fine weather"), air pressure changes ("rising quickly") and the 16 points of the compass ("NNE"). Leave the "(%Z)" in "Time (%Z)" unchanged and make sure your translation's punctuation matches the original. The other files contain strings from the pywws documentation. These are in `reStructuredText `_. This is mostly plain text, but uses characters such as backquotes (\`), colons (\:) and asterisks (\*) for special purposes. You need to take care to preserve this special punctuation. Do not translate program source, computer instructions and cross-references like these:: `pip `_ :py:class:`datetime.datetime` :obj:`ParamStore `\\ (root_dir, file_name) pywws.Forecast ``pywws-livelog`` Translating all of the pywws documentation is a lot of work. However, when the documentation is "compiled" any untranslated strings revert to their English original. This means that a partial translation could still be useful -- I suggest starting with the documentation front page, ``index.po``. Send Jim the translation ------------------------ I'm sure you would like others to benefit from the work you've done in translating pywws. If you've been using Transifex then please send me an email (jim@jim-easterbrook.me.uk) to let me know there's a new translation available. Otherwise, please email me any ``.po`` files you create. pywws-24.2.0/src/doc/guides/livelogging.rst0000644000200200001440000003153613351134756020611 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-18 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. How to set up 'live' logging with pywws ======================================= Introduction ------------ There are two quite different modes of operation with pywws. Traditionally :py:mod:`pywws.hourly` would be run at regular intervals (usually an hour) from cron. This is suitable for fairly static websites, but more frequent updates can be useful for sites such as Weather Underground (http://www.wunderground.com/). The newer :py:mod:`pywws.livelog` program runs continuously and can upload data every 48 seconds. Getting started --------------- First of all, you need to install pywws and make sure it can get data from your weather station. See :doc:`getstarted` for details. If you have previously been using :py:mod:`pywws.hourly` then disable your 'cron' job (or whatever else you use to run it) so it no longer runs. You should never run :py:mod:`pywws.hourly` and :py:mod:`pywws.livelog` at the same time. Try running :py:mod:`pywws.livelog` from the command line, with a high level of verbosity so you can see what's happening. Use the ``pywws-livelog`` command to run :py:mod:`pywws.livelog`:: pywws-livelog -vvv ~/weather/data Within five minutes (assuming you have set a 5 minute logging interval) you should see a 'live_data new ptr' message, followed by fetching any new data from the weather station and processing it. Let :py:mod:`pywws.livelog` run for a minute or two longer, then kill the process by typing 'C'. .. versionchanged:: 14.04.dev1194 the ``pywws-livelog`` command replaced ``scripts/pywws-livelog.py``. Configuring file locations -------------------------- Open your weather.ini file with a text editor. You should have a ``[paths]`` section similar to the following (where ``xxx`` is your user name):: [paths] work = /tmp/pywws templates = /home/xxx/weather/templates/ graph_templates = /home/xxx/weather/graph_templates/ modules = /home/xxx/weather/modules/ Edit these to suit your installation and preferences. ``work`` is a temporary directory used to store intermediate files. If your computer uses solid state storage, such as a Raspberry Pi's SD card, it's a good idea to make this a "RAM disk" to reduce storage "wear". ``templates`` is the directory where you keep your text template files, ``graph_templates`` is the directory where you keep your graph template files, and ``modules`` is a directory for any extra modules you write. Don't use the pywws example directories for your templates, as they will get over-written when you upgrade pywws. Copy your text and graph templates to the appropriate directories. You may find some of the examples provided with pywws useful to get started. The ``pywws-version -v`` command should show you where the examples are on your computer. .. versionadded:: 14.04.dev1194 the ``pywws-version`` command. Configuring periodic tasks -------------------------- In weather.ini you should have a ``[live]`` section similar to the following:: [live] services = [] text = [] plot = [] This section specifies what pywws should do every time it gets a new reading from the weather station, i.e. every 48 seconds. The ``services`` entry is a list of online weather services to upload data to, e.g. ``'underground'`` or ``('ftp', '24hrs.txt')``. The ``plot`` and ``text`` entries are lists of template files for plots and text files to be processed. You should probably leave all of these blank except for ``services``. If you use YoWindow (http://yowindow.com/) you can add an entry to the ``[live]`` section to specify your YoWindow file, e.g.:: [live] services = ['underground'] text = ['yowindow.xml'] plot = [] If you don't already have them, create four more sections in your weather.ini file: ``[logged]``, ``[hourly]``, ``[12 hourly]`` and ``[daily]``. These sections should have similar entries to the ``[live]`` section, and specify what to do every time data is logged (5 to 30 minutes, depending on your logging interval), every hour, twice daily and once per day. Add the names of your template files to the appropriate entries, for example:: [logged] services = ['underground', 'metoffice'] plot = [] text = [] [hourly] services = [('twitter', 'tweet.txt'), ('ftp', '7days.png', '24hrs.png', 'rose_24hrs.png', '24hrs.txt', '6hrs.txt', '7days.txt')] plot = ['7days.png.xml', '24hrs.png.xml', 'rose_24hrs.png.xml'] text = ['tweet.txt', '24hrs.txt', '6hrs.txt', '7days.txt'] [12 hourly] services = [] plot = [] text = [] [daily] services = [('twitter', 'forecast.txt'), ('ftp', '28days.png', 'allmonths.txt')] plot = ['28days.png.xml'] text = ['forecast.txt', 'allmonths.txt'] Note that the ``twitter`` and ``ftp`` "services" use files generated by the ``plot`` and ``text`` items. It's probably best not to add all of these at once. You could start by uploading one file to your web site, then when that's working add the remaining web site files. You can add Twitter and other services later on. .. versionadded:: 14.05.dev1211 ``[cron name]`` sections. If you need more flexibility in when tasks are done you can use ``[cron name]`` sections. See :doc:`weather_ini` for more detail. Create a dedicated user (optional) ---------------------------------- As pywws will be running continuously, and contacting various computers on the internet, there is a very remote risk that one of its dependencies has a security flaw that might allow someone to gain unauthorised to your computer. Running pywws as a user with minimal privileges adds a little extra protection. You can create a user with the ``adduser`` command:: sudo adduser --system --disabled-login --shell=/bin/false pywws The exact syntax may vary according to your operating system. The important thing is to create a user that can't login, and can't run ``sudo``, but does have a home directory. Run in the background --------------------- In order to have :py:mod:`pywws.livelog` carry on running after you finish using your computer it needs to be run as a "background job". On most Linux / UNIX systems you can do this by putting an ampersand ('&') at the end of the command line. Running a job in the background like this doesn't always work as expected: the job may suspend when you log out. It's much better to run as a proper UNIX 'daemon' process. Using systemd ^^^^^^^^^^^^^ On recent versions of Linux the systemd_ service manager makes it easy to create a daemon process. The service is defined in a file ``/etc/systemd/system/pywws.service``:: [Unit] Description=pywws weather station live logging After=time-sync.target [Service] Type=simple User=pywws Restart=on-failure ExecStart=/usr/local/bin/pywws-livelog -v -l systemd /home/pywws/data/ The ``[Unit]`` section says pywws shouldn't start until the computer has set its clock correctly. This is important on computers without a battery-backed real time clock, such as the Raspberry Pi. The ``[Service]`` section specifies which user should run pywws and gives the command to run it. The ``-l systemd`` option sends log messages to ``systemd`` instead of using a normal pywws log file. You can use ``sudo service pywws start`` to test the ``pywws.service`` file. After starting ``sudo service pywws status`` shows if it's running OK, and the last few log messages:: jim@gordon:~ $ sudo service pywws status ● pywws.service - pywws weather station live logging Loaded: loaded (/etc/systemd/system/pywws.service; static; vendor preset: enabled) Active: active (running) since Thu 2018-08-23 17:49:01 BST; 12min ago Main PID: 30946 (pywws-livelog) CGroup: /system.slice/pywws.service └─30946 /usr/bin/python3 /usr/local/bin/pywws-livelog -v -l systemd /home/pywws/data/ Aug 23 17:49:44 gordon pywws-livelog[30946]: pywws.service.wetterarchivde:server response "{'version': '6.0', 'status': 'SUCCESS'}" Aug 23 17:49:44 gordon pywws-livelog[30946]: pywws.service.metoffice:OK Aug 23 17:49:45 gordon pywws-livelog[30946]: pywws.service.openweathermap:OK Aug 23 17:49:46 gordon pywws-livelog[30946]: pywws.service.cwop:OK Aug 23 17:49:46 gordon pywws-livelog[30946]: pywws.service.underground:server response "success" Aug 23 17:57:41 gordon pywws-livelog[30946]: pywws.weatherstation:setting sensor clock 5.33264 Aug 23 17:57:41 gordon pywws-livelog[30946]: pywws.weatherstation:sensor clock drift 1.4672 1.08387 Aug 23 18:00:25 gordon pywws-livelog[30946]: pywws.service.mastodon:OK Aug 23 18:00:26 gordon pywws-livelog[30946]: pywws.service.twitter:OK Aug 23 18:00:26 gordon pywws-livelog[30946]: pywws.service.sftp:OK jim@gordon:~ $ If you'd prefer to use a normal pywws log file the ``pywws.service`` file might look like this:: [Unit] Description=pywws weather station live logging After=time-sync.target [Service] Type=simple User=pywws Restart=on-failure PermissionsStartOnly=true ExecStartPre=/bin/mkdir -p /var/log/pywws ExecStartPre=/bin/chown -R pywws:nogroup /var/log/pywws/ ExecStart=/usr/local/bin/pywws-livelog -v -l /var/log/pywws/pywws.log /home/pywws/data/ In this example the log file is ``/var/log/pywws/pywws.log``. The directory ``/var/log/pywws/`` might not exist after a reboot (e.g. if ``/var/log/`` has been moved to RAM disk to reduce SD card wear) so ``ExecStartPre`` is used to create it and transfer its ownership to the ``pywws`` user. ``PermissionsStartOnly=true`` ensures the ``ExecStartPre`` commands are run as root. The udev_ system can be used to start the pywws service when the computer boots or the weather station is plugged into the USB port. (It also stops pywws if the weather station is unplugged.) Create a file ``/etc/udev/rules.d/39-weather-station.rules`` as follows:: SUBSYSTEM=="usb" \ , ATTRS{idVendor}=="1941" \ , ATTRS{idProduct}=="8021" \ , OWNER="pywws" \ , TAG+="systemd" \ , ENV{SYSTEMD_WANTS}="pywws.service" This sets the owner of the weather station's USB port to ``pywws``, then adds ``pywws.service`` to the things ``systemd`` should be running. Using pywws-livelog-daemon ^^^^^^^^^^^^^^^^^^^^^^^^^^ If you can't use systemd_ for some reason then the :py:mod:`pywws.livelogdaemon` program can be used to run pywws as a daemon, if you have the `python-daemon `_ library installed:: pywws-livelog-daemon -v ~/weather/data ~/weather/data/pywws.log start (Note that the log file is a required parameter, not an option.) Unfortunately the python-daemon package appears not to be maintained, and I've had problems with it on some Linux versions. You'll also need to setup something to start pywws automatically. There are various ways of configuring a Linux system to start a program when the machine boots up. Typically these involve putting a file in ``/etc/init.d/``. A slightly harder problem is ensuring a program restarts if it crashes. My solution to both problems is to run the following script from cron, several times an hour. :: #!/bin/sh export PATH=$PATH:/usr/local/bin # exit if NTP hasn't set computer clock [ `ntpdc -c sysinfo | awk '/stratum:/ {print $2}'` -ge 10 ] && exit pidfile=/var/run/pywws.pid datadir=/home/jim/weather/data logfile=$datadir/live_logger.log # exit if process is running [ -f $pidfile ] && kill -0 `cat $pidfile` && exit # email last few lines of the logfile to see why it died if [ -f $logfile ]; then log=/tmp/log-weather tail -40 $logfile >$log /home/jim/scripts/email-log.sh $log "weather log" rm $log fi # restart process pywws-livelog-daemon -v -p $pidfile $datadir $logfile start The process id of the daemon is stored in ``pidfile``. If the process is running, the script does nothing. If the process has crashed, it emails the last 40 lines of the log file to me (using a script that creates a message and passes it to sendmail) and then restarts :py:mod:`pywws.livelogdaemon`. You'll need to edit this quite a lot to suit your file locations and so on, but it gives some idea of what to do. .. _systemd: https://en.wikipedia.org/wiki/Systemd .. _udev: https://en.wikipedia.org/wiki/Udev pywws-24.2.0/src/doc/guides/logfiles.rst0000644000200200001440000006164713305436032020104 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2015-18 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Understanding pywws log files ============================= The pywws software uses Python's logging system to report errors, warnings and information that may be useful in diagnosing problems. When you run the software interactively these messages are sent to your terminal window, when running a daemon process or cron job they should be written to a log file. This document explains some of the pywws logging messages. It's not a complete guide, and the messages you see will depend on your weather station and configuration, but it should help you understand some of the more common ones. Many pywws commands have a ``-v`` or ``--verbose`` option to increase the verbosity of the logging messages. This option can be repeated for even more verbosity, which may be useful when trying to diagnose a particular fault. Here are some typical logging outputs. The first shows pywws being run interactively: .. code-block:: none :linenos: jim@gordon:~ $ pywws-livelog -v ~/weather/data/ 09:25:11:pywws.logger:pywws version 18.5.0, build 1541 (d505b50) 09:25:11:pywws.logger:Python version 3.5.3 (default, Jan 19 2017, 14:11:04) [GCC 6.3.0 20170124] 09:25:12:pywws.weatherstation:using pywws.device_libusb1 09:25:17:pywws.calib:Using user calibration 09:25:46:pywws.weatherstation:status {'rain_overflow': False, 'lost_connection': False} 09:25:53:pywws.regulartasks:doing task sections ['live'] 09:25:54:pywws.service.openweathermap:OK 09:25:54:pywws.service.openweathermap:1 record sent 09:25:55:pywws.service.underground:server response "success" 09:25:55:pywws.service.underground:1 record sent 09:26:41:pywws.regulartasks:doing task sections ['live'] 09:26:42:pywws.service.openweathermap:1 record sent 09:26:44:pywws.service.underground:1 record sent 09:27:29:pywws.regulartasks:doing task sections ['live'] 09:27:30:pywws.service.openweathermap:1 record sent 09:27:33:pywws.service.underground:1 record sent 09:28:17:pywws.regulartasks:doing task sections ['live'] 09:28:19:pywws.service.openweathermap:1 record sent 09:28:22:pywws.service.underground:1 record sent 09:29:05:pywws.regulartasks:doing task sections ['live'] 09:29:07:pywws.service.openweathermap:1 record sent 09:29:07:pywws.service.underground:1 record sent 09:29:16:pywws.weatherstation:live_data new ptr: 0053a0 09:29:16:pywws.process:Generating summary data 09:29:17:pywws.regulartasks:doing task sections ['logged'] 09:29:17:pywws.service.wetterarchivde:server response "{'version': '6.0', 'status': 'SUCCESS'}" 09:29:17:pywws.service.wetterarchivde:1 record sent 09:29:17:pywws.service.cwop:OK 09:29:17:pywws.service.cwop:1 record sent 09:29:20:pywws.service.metoffice:OK 09:29:20:pywws.service.metoffice:1 record sent Note that each line begins with a time stamp, in local time. Line 1 is the command used to start pywws. Line 2 shows the pywws version. Line 3 shows the Python version. Line 4 shows which Python USB library is being used. Line 5 shows that a :py:mod:`"user calibration" ` routine is being used. Line 6 shows the current value of the weather station "status" bits. This will be shown again if the status changes. Lines 7, 12, 15, 18 & 21 show that tasks in the ``[live]`` section of ``weather.ini`` are being executed. You can see from the time stamps that they happen at 48 second intervals. Line 24 shows that the station has "logged" data and moved on to the next memory address. pywws then generates summary data and executes tasks in the ``[logged]`` section of ``weather.ini``. The remaining lines show uploads to various weather "services" (see :doc:`integration`). Uploads to ``openweathermap`` and ``underground`` are done every 48 seconds. Uploads to ``wetterarchivde``, ``cwop``, and ``metoffice`` are less frequent. The first upload to a service logs ``OK`` or a message from the server. This is not shown again unless the response changes. When running pywws as a daemon process the logging is less verbose: .. code-block:: none 2018-05-27 10:50:40:pywws.logger:pywws version 18.5.0, build 1541 (d505b50) 2018-05-27 10:51:19:pywws.weatherstation:status {'lost_connection': False, 'rain_overflow': False} 2018-05-27 10:54:19:pywws.service.cwop:1 record(s) dropped 2018-05-27 10:54:19:pywws.service.cwop:OK 2018-05-27 10:54:19:pywws.service.wetterarchivde:server response "{'version': '6.0', 'status': 'SUCCESS'}" 2018-05-27 10:54:19:pywws.service.wetterarchivde:2 records sent 2018-05-27 10:54:20:pywws.service.openweathermap:OK 2018-05-27 10:54:20:pywws.service.openweathermap:2 records sent 2018-05-27 10:54:20:pywws.service.underground:server response "success" 2018-05-27 10:54:20:pywws.service.metoffice:OK 2018-05-27 10:54:20:pywws.service.underground:2 records sent 2018-05-27 10:54:21:pywws.service.metoffice:2 records sent 2018-05-27 11:00:31:pywws.towebsite:OK 2018-05-27 11:00:33:pywws.totwitter:OK 2018-05-27 11:54:14:pywws.weatherstation:setting station clock 14.371 2018-05-27 11:54:14:pywws.weatherstation:station clock drift -0.499934 -0.401405 2018-05-27 14:00:36:pywws.towebsite:[Errno 111] Connection refused 2018-05-27 14:01:16:pywws.towebsite:OK 2018-05-27 15:00:34:pywws.towebsite:[Errno 111] Connection refused 2018-05-27 15:17:25:pywws.towebsite:[Errno 110] Connection timed out 2018-05-27 15:18:05:pywws.towebsite:OK 2018-05-28 01:05:47:pywws.weatherstation:setting sensor clock 11.1295 2018-05-28 01:05:47:pywws.weatherstation:sensor clock drift 1.02042 0.987513 2018-05-28 01:10:29:pywws.service.metoffice:HTTPConnectionPool(host='wow.metoffice.gov.uk', port=80): Read timed out. (read timeout=60) 2018-05-28 01:11:09:pywws.service.metoffice:repeated data 2018-05-28 00:09:14 2018-05-28 01:14:25:pywws.service.metoffice:OK 2018-05-28 01:50:31:pywws.service.metoffice:HTTPConnectionPool(host='wow.metoffice.gov.uk', port=80): Read timed out. (read timeout=60) 2018-05-28 01:52:52:pywws.service.metoffice:repeated data 2018-05-28 00:49:14 2018-05-28 01:55:22:pywws.service.metoffice:HTTPConnectionPool(host='wow.metoffice.gov.uk', port=80): Read timed out. (read timeout=60) 2018-05-28 01:57:42:pywws.service.metoffice:OK 2018-05-28 09:00:38:pywws.totwitter:2 records sent 2018-05-28 10:50:07:pywws.service.metoffice:HTTPConnectionPool(host='wow.metoffice.gov.uk', port=80): Read timed out. (read timeout=60) 2018-05-28 10:50:47:pywws.service.metoffice:OK 2018-05-28 11:59:14:pywws.weatherstation:setting station clock 14.0721 2018-05-28 11:59:14:pywws.weatherstation:station clock drift -0.297843 -0.375514 2018-05-28 19:44:20:pywws.weatherstation:live_data log extended Each line begins with a date and time stamp, in local time. Because pywws hadn't been run for 10 minutes each service starts by uploading 2 "catchup" records, except ``cwop`` which only accepts live data so one record is dropped. At 11:00 am the first ``[hourly]`` tasks are run, uploading to a website and sending to Twitter. The 14:00 and 15:00 website uploads failed, but were successful later on. The ``metoffice`` upload at 01:10:29 appeared to fail, but when it was retried at 01:11:09 the server said it already had the data. (Note the data timestamp is in UTC, the log message time stamp is in BST, one hour ahead.) The remaining lines show status messages that are described in more detail below. Clock drift ----------- .. code-block:: none 2018-05-28 01:05:47:pywws.weatherstation:setting sensor clock 11.1295 2018-05-28 01:05:47:pywws.weatherstation:sensor clock drift 1.02042 0.987513 2018-05-28 11:59:14:pywws.weatherstation:setting station clock 14.0721 2018-05-28 11:59:14:pywws.weatherstation:station clock drift -0.297843 -0.375514 These lines report how the weather station's internal ("station") and external ("sensor") clocks are drifting with respect to the computer's clock. (The ``3080`` class stations also have a "solar" clock as the sunlight data is sent at 60 second intervals.) These measurements are used to avoid accessing the station's USB port at the same time as it is receiving data or logging data, as this is known to cause some stations' USB ports to become inaccessible. The two "drift" figures are the current value (only accurate to about 1 second) and the long term average. You should ensure that the ``usb activity margin`` value in your :ref:`weather.ini file ` is at least 0.5 seconds greater than the absolute value of the long term drift of each clock. Note that these drift values change with temperature. The clock drifts are measured at approximately 24 hour intervals. If pywws loses synchronisation with your station it will measure them again. Doing this measurement increases the risk of causing a USB lockup, so if pywws often loses synchronisation you should try and find out why it's happening. Network problems ---------------- Occasionally one or more of the services and web sites you upload data to may become unavailable. This leads to error messages like these: .. code-block:: none 2018-05-28 21:03:02:pywws.service.underground:HTTPSConnectionPool(host='rtupdate.wunderground.com', port=443): Max retries exceeded with url: /weatherstation/updateweatherstation.php?rtfreq=48&winddir=5&softwaretype=pywws&windspeedmph=0.67&tempf=68.7&dateutc=2018-05-28+20%3A02%3A35&dewptf=65.3&action=updateraw&ID=ISURREYE4&windgustmph=2.24&PASSWORD=xxxxxxxx&baromin=30.0910&humidity=89&realtime=1&dailyrainin=0.122173&rainin=0 (Caused by NewConnectionError(': Failed to establish a new connection: [Errno -2] Name or service not known',)) 2018-05-28 21:03:15:pywws.service.openweathermap:HTTPConnectionPool(host='api.openweathermap.org', port=80): Max retries exceeded with url: /data/3.0/measurements?appid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (Caused by NewConnectionError(': Failed to establish a new connection: [Errno 101] Network is unreachable',)) 2018-05-29 20:38:42:pywws.service.underground:http status: 500 2018-05-29 20:39:23:pywws.service.underground:server response "success" 2018-05-30 18:19:59:pywws.service.wetterarchivde:http status: 504 2018-05-30 18:20:39:pywws.service.wetterarchivde:server response "{'info': 'Report exists at 2018-05-30T17:19:00.000Z', 'version': '6.0', 'status': 'SUCCESS', 'log': 'dbea2445-d930-4053-89ea-20c04a5030c1'}" 2018-05-30 18:24:17:pywws.service.wetterarchivde:server response "{'version': '6.0', 'status': 'SUCCESS'}" 2018-05-31 01:50:04:pywws.service.openweathermap:('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer')) 2018-05-31 01:50:44:pywws.service.openweathermap:OK To avoid swamping the log files duplicate messages are not logged. When the response changes it is logged again. Status ------ .. code-block:: none 2015-09-01 21:50:21:pywws.weather_station:status {'lost_connection': True, 'rain_overflow': False} The raw weather station data includes some "status" bits. If any of these bits changes value when pywws is running, the status value is logged. The most common problem is ``lost_connection``: the weather station console is not receiving data from the outside sensors. Contact is often restored a few minutes later, but if not you may need to reset your weather station console by taking its batteries out. The ``rain_overflow`` bit is set when the rain gauge counter has reached its maximum value and gone back to zero. There are 6 bits of data in the status byte whose function is not yet known. If any of these bits is set the value will be added to the reported status. Do let me know if this happens as it might enable us to find the meaning of the unused bits. Log extended ------------ .. code-block:: none 2018-05-29 22:16:19:pywws.weatherstation:live_data log extended 2018-05-29 22:32:19:pywws.weatherstation:live_data log extended 2018-05-29 22:48:19:pywws.weatherstation:live_data log extended 2018-05-29 23:04:19:pywws.weatherstation:live_data log extended This shows a curiosity in the weather station's internal processing. As the internal and external sensors drift there comes a time when an external reading is expected at the same time as the station is due to log some data. To avoid a clash the station delays logging by one minute. As the external readings are at 48 second intervals this avoids the problem until 16 minutes later (with the normal 5 minute logging interval) when another one minute delay is needed. Eventually the clocks drift apart and normal operation is resumed. The ``3080`` class stations also receive solar data at 60 second intervals. If this clashes with the logging time the station delays logging by one minute. Unfortunately this doesn't help, so the station effectively stops logging data until the clocks drift apart again. If you are running pywws "live logging" then it will cover the gap by saving live readings at five minute intervals (if your logging interval is set to five minutes) until the station resumes normal operation. If you are running "hourly" logging then you may get a large gap in your data. Rain reset ---------- .. code-block:: none 2015-08-25 13:30:51:pywws.process:2015-08-25 12:30:48 rain reset 1048.4 -> 1047.1 2015-08-25 13:35:51:pywws.process:2015-08-25 12:30:48 rain reset 1048.4 -> 1047.1 2015-08-25 13:40:51:pywws.process:2015-08-25 12:30:48 rain reset 1048.4 -> 1047.1 The raw rainfall data from the outside sensors is the total number of times the "see saw" has tipped since the external sensors were last reset (by a battery change, unless you do it quickly). This number should only ever increase, so the :py:mod:`pywws.process` module warns of any decrease in the value as it may indicate corrupted data that needs manually correcting. The logging message includes the UTC time stamp of the problem data to help you find it. Live data missed ---------------- .. code-block:: none 2015-10-30 04:49:56:pywws.weatherstation:live_data missed Sometimes pywws fails to capture live data. This happens if a new data record is identical to the previous one so pywws doesn't detect a change. This is unlikely to happen if you are receiving wind data properly. Note that this is just an occasional missing "live" record though, so if it does not happen often you shouldn't worry too much about it. "Live log" synchronisation -------------------------- If you run pywws at a high verbosity you may see messages like the following: .. code-block:: none jim@gordon:~ $ pywws-livelog -vv ~/weather/data/ 10:32:46:pywws.logger:pywws version 18.5.0, build 1541 (d505b50) 10:32:46:pywws.logger:Python version 3.5.3 (default, Jan 19 2017, 14:11:04) [GCC 6.3.0 20170124] 10:32:46:pywws.weatherstation:using pywws.device_libusb1 10:32:48:pywws.calib:Using user calibration 10:32:51:pywws.weatherstation:read period 5 10:32:51:pywws.weatherstation:delay 3, pause 0.5 10:32:52:pywws.weatherstation:status {'rain_overflow': False, 'lost_connection': False} 10:32:52:pywws.weatherstation:delay 3, pause 0.5 10:32:53:pywws.weatherstation:delay 3, pause 0.5 10:32:54:pywws.weatherstation:delay 3, pause 0.5 10:32:54:pywws.weatherstation:delay 3, pause 0.5 10:32:55:pywws.weatherstation:delay 3, pause 0.5 10:32:56:pywws.weatherstation:delay 3, pause 0.5 10:32:56:pywws.weatherstation:delay 3, pause 0.5 10:32:57:pywws.weatherstation:delay 3, pause 0.5 10:32:58:pywws.weatherstation:delay 3, pause 0.5 10:32:58:pywws.weatherstation:delay 3, pause 0.5 10:32:59:pywws.weatherstation:delay 3, pause 0.5 10:33:00:pywws.weatherstation:delay 3, pause 0.5 10:33:00:pywws.weatherstation:delay 3, pause 0.5 10:33:01:pywws.weatherstation:delay 3, pause 0.5 10:33:02:pywws.weatherstation:delay 3, pause 0.5 10:33:02:pywws.weatherstation:live_data new data 10:33:02:pywws.weatherstation:setting sensor clock 14.7283 10:33:02:pywws.regulartasks:doing task sections ['live'] 10:33:03:pywws.service.underground:thread started Thread-2 10:33:03:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): rtupdate.wunderground.com 10:33:03:pywws.service.openweathermap:thread started Thread-4 10:33:03:pywws.weatherstation:delay 3, pause 43.4936 10:33:03:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): api.openweathermap.org 10:33:03:requests.packages.urllib3.connectionpool:http://api.openweathermap.org:80 "POST /data/3.0/measurements?appid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx HTTP/1.1" 204 0 10:33:03:pywws.service.openweathermap:OK 10:33:03:pywws.service.openweathermap:1 record sent 10:33:04:requests.packages.urllib3.connectionpool:https://rtupdate.wunderground.com:443 "GET /weatherstation/updateweatherstation.php?baromin=29.9877&dewptf=63.2&ID=ISURREYE4&action=updateraw&dailyrainin=0&windgustmph=3.13&softwaretype=pywws&winddir=48&tempf=68.5&dateutc=2018-05-31+09%3A33%3A02&realtime=1&windspeedmph=1.57&humidity=83&rtfreq=48&PASSWORD=xxxxxxxxxxxx&rainin=0 HTTP/1.1" 200 8 10:33:04:pywws.service.underground:server response "success" 10:33:04:pywws.service.underground:1 record sent 10:33:47:pywws.weatherstation:delay 3, pause 0.5 10:33:47:pywws.weatherstation:avoid 5.795123949846001 10:33:53:pywws.weatherstation:live_data new data 10:33:53:pywws.regulartasks:doing task sections ['live'] 10:33:54:pywws.weatherstation:delay 4, pause 15.0615 10:33:56:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): api.openweathermap.org 10:33:56:requests.packages.urllib3.connectionpool:http://api.openweathermap.org:80 "POST /data/3.0/measurements?appid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx HTTP/1.1" 204 0 10:33:56:pywws.service.openweathermap:OK 10:33:56:pywws.service.openweathermap:1 record sent 10:33:56:requests.packages.urllib3.connectionpool:Starting new HTTPS connection (1): rtupdate.wunderground.com 10:33:57:requests.packages.urllib3.connectionpool:https://rtupdate.wunderground.com:443 "GET /weatherstation/updateweatherstation.php?baromin=29.9877&dewptf=63.2&ID=ISURREYE4&action=updateraw&dailyrainin=0&windgustmph=2.24&softwaretype=pywws&winddir=38&tempf=68.5&dateutc=2018-05-31+09%3A33%3A50&realtime=1&windspeedmph=0.67&humidity=83&rtfreq=48&PASSWORD=xxxxxxxxxxxx&rainin=0 HTTP/1.1" 200 8 10:33:57:pywws.service.underground:server response "success" 10:33:57:pywws.service.underground:1 record sent 10:34:09:pywws.weatherstation:delay 4, pause 0.5 10:34:10:pywws.weatherstation:avoid 5.808650196657673 10:34:16:pywws.weatherstation:live_data new ptr: 005470 10:34:16:pywws.process:Generating summary data 10:34:16:pywws.process:daily: 2018-05-31 09:00:00 10:34:16:pywws.process:monthly: 2018-05-01 09:00:00 10:34:16:pywws.regulartasks:doing task sections ['logged'] 10:34:16:pywws.service.cwop:thread started Thread-1 10:34:17:pywws.service.wetterarchivde:thread started Thread-3 10:34:17:pywws.service.metoffice:thread started Thread-5 10:34:17:pywws.weatherstation:delay 0, pause 18.132 10:34:17:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): interface.wetterarchiv.de 10:34:17:requests.packages.urllib3.connectionpool:Starting new HTTP connection (1): wow.metoffice.gov.uk 10:34:17:requests.packages.urllib3.connectionpool:http://interface.wetterarchiv.de:80 "POST /weather/ HTTP/1.1" 200 36 10:34:17:pywws.service.wetterarchivde:server response "{'status': 'SUCCESS', 'version': '6.0'}" 10:34:17:pywws.service.wetterarchivde:1 record sent 10:34:17:pywws.service.cwop:server software: b'# javAPRSSrvr 4.3.0b17' 10:34:17:pywws.service.cwop:login: "user EW4610 pass -1 vers pywws 18.5.0" 10:34:17:pywws.service.cwop:packet: "EW4610>APRS,TCPIP*:@310934z5121.90N/00015.07W_038/001g002t069r000p000b10155h83.pywws-18.5.0" 10:34:17:pywws.service.cwop:server login ack: b'# logresp EW4610 unverified, server CWOP-2' 10:34:17:pywws.service.cwop:OK 10:34:17:pywws.service.cwop:1 record sent 10:34:17:requests.packages.urllib3.connectionpool:http://wow.metoffice.gov.uk:80 "GET /automaticreading?baromin=29.9877&dewptf=63.2&softwaretype=pywws-18.5.0&dailyrainin=0.0000&windgustmph=2.24&siteid=18837259&winddir=38&tempf=68.5&dateutc=2018-05-31+09%3A34%3A13&windspeedmph=0.67&humidity=83&siteAuthenticationKey=xxxxxx&rainin=0.0000 HTTP/1.1" 200 2 10:34:17:pywws.service.metoffice:OK 10:34:17:pywws.service.metoffice:1 record sent ^C10:34:21:pywws.storage:waiting for thread Thread-2 10:34:21:pywws.storage:waiting for thread Thread-4 10:34:21:pywws.storage:waiting for thread Thread-3 10:34:21:pywws.storage:waiting for thread Thread-1 10:34:21:pywws.storage:waiting for thread Thread-5 10:34:21:pywws.storage:flushing The "read period" message at 10:32:51 shows that the weather station has the usual 5 minute logging interval. The "delay 3, pause 0.5" messages show pywws waiting for the station to receive data from the outside sensors. The ``delay`` value is the number of minutes since the station last logged some data. The ``pause`` value is how many seconds pywws will wait before fetching data from the station again. At 10:33:02 new data is received and the "sensor" clock is set. After initiating uploads to ``underground`` and ``openweathermap`` the live logging loop sleeps for 43 seconds. The uploads happen in their own threads while the main loop is paused. At 10:33:47 the main loop resumes polling the station. Almost immediately it pauses for 5.8 seconds to avoid USB activity around the time the station should receive external data. At 10:34:10 USB activity is avoided when the station is expected to "log" data. At 10:34:16 the new memory pointer is detected and the logged data is processed. At 10:34:21 I pressed ``Ctrl-C`` to terminate the program. After shutting down the upload threads any unsaved data is flushed to file and the program finishes. Crash with traceback -------------------- Sometimes pywws software crashes. When it does, the log file will often contain a traceback like this: .. code-block:: none :linenos: 2018-05-31 11:13:47:pywws.livelog:LIBUSB_ERROR_IO [-1] Traceback (most recent call last): File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/livelog.py", line 70, in live_log logged_only=(not tasks.has_live_tasks())): File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/logdata.py", line 245, in live_data for data, ptr, logged in self.ws.live_data(logged_only=logged_only): File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/weatherstation.py", line 546, in live_data new_ptr = self.current_pos() File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/weatherstation.py", line 704, in current_pos self._read_fixed_block(0x0020), self.lo_fix_format['current_pos']) File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/weatherstation.py", line 760, in _read_fixed_block result += self._read_block(mempos) File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/weatherstation.py", line 748, in _read_block new_block = self.cusb.read_block(ptr) File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/weatherstation.py", line 342, in read_block if not self.dev.write_data(buf): File "/usr/local/lib/python3.5/dist-packages/pywws-18.5.0-py3.5.egg/pywws/device_libusb1.py", line 131, in write_data 0x200, 0, str_buf, timeout=50) File "/usr/lib/python3/dist-packages/usb1/__init__.py", line 1390, in controlWrite sizeof(data), timeout) File "/usr/lib/python3/dist-packages/usb1/__init__.py", line 1366, in _controlTransfer mayRaiseUSBError(result) File "/usr/lib/python3/dist-packages/usb1/__init__.py", line 133, in mayRaiseUSBError __raiseUSBError(value) File "/usr/lib/python3/dist-packages/usb1/__init__.py", line 125, in raiseUSBError raise __STATUS_TO_EXCEPTION_DICT.get(value, __USBError)(value) usb1.USBErrorIO: LIBUSB_ERROR_IO [-1] Line 1 shows the exception that caused the crash. Lines 3 to 26 show where in the program the problem happened. Usually the last one is of interest, but the other function calls show how we got there. Line 27 shows the full exception. In this case it's a USBError raised by the libusb1 library. pywws-24.2.0/src/doc/guides/weather_ini.rst0000644000200200001440000003543013455305356020577 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-18 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. weather.ini - configuration file format ======================================= Nearly all configuration of pywws is via a single file in the data directory: weather.ini. This file has a structure similar to that of Microsoft Windows INI files. It is divided into "sections", each of which has a number of "name = value" entries. The order in which sections appear is not important. Any plain text editor can be used to do edit the file. (Don't try to edit it while any other pywws software is running.) In many cases pywws will initialise the entries to sensible values. Another file, status.ini, is used to store some information that pywws uses internally. It is described at the end of this document. In normal use you should not need to edit it. The following sections are currently in use: * config: miscellaneous system configuration. * paths: directories in which templates etc. are stored. * live: tasks to be done every 48 seconds. * logged: tasks to be done every time the station logs a data record. * cron: tasks to be done at a particular time or date. * hourly: tasks to be done every hour. * 12 hourly: tasks to be done every 12 hours. * daily: tasks to be done every day. * ftp: configuration of uploading to a website. * underground, metoffice, temperaturnu etc: configuration of posting to 'services'. .. _weather_ini-config: config: miscellaneous system configuration ------------------------------------------ :: [config] ws type = 1080 day end hour = 9, False pressure offset = 9.4 gnuplot encoding = utf8 template encoding = iso-8859-1 language = en_GB logdata sync = 1 rain day threshold = 0.2 usb activity margin = 3.0 gnuplot version = 4.6 frequent writes = False ``ws type`` is the "class" of weather station. It should be set to ``1080`` for most weather stations, or ``3080`` if your station console displays solar illuminance. ``day end hour`` is the end of the "`meteorological day `_", in local time, and whether daylight savings time should be applied. Typical values are ``9, False`` (UK Met Office standard) or ``0, True`` (midnight, summer and winter). Note that using daylight savings time will mean that one day a year is 25 hours long and one is 23 hours long. You must update all your stored data by running :py:mod:`pywws.reprocess` after you change this value. ``pressure offset`` is added to the absolute air pressure to get the relative (sea level) air pressure, unit: hPa. The initial value is copied from the weather station, assuming you have set it up to display the correct relative pressure, but you can adjust the value in weather.ini to calibrate your station. You can calculate this value or use the difference to a trusted weatherstation or weather service nearby. You must update all your stored data by running :py:mod:`pywws.reprocess` after you change this value. .. versionchanged:: 13.10_r1082 made ``pressure offset`` a config item. Previously it was always read from the weather station. ``gnuplot encoding`` is the text encoding used when plotting graphs. The default value of ``iso_8859_1`` allows the degree symbol, which is useful in a weather application! Other values might be needed if your language includes accented characters. The possible values depend on your gnuplot installation so some experimentation may be needed. ``template encoding`` is the text encoding used for templates. The default value is ``iso-8859-1``, which is the encoding used in most of the example templates. If you create templates with a different character set, you should change this value to match your templates. ``language`` is used to localise pywws. It's optional, as pywws usually uses the computer's default language as set by the LANG environment variable. The available languages are those in the ``translations`` subdirectory of your pywws installation. If you set any other language, pywws will fall back to using English. ``logdata sync`` sets the quality of synchronisation used by :doc:`../api/pywws.logdata`. Set it to 0 for fast & inaccurate or 1 for slower but precise. ``rain day threshold`` is the amount of rain (in mm) that has to fall in one day for it to qualify as a rainy day in the monthly summary data. You must update all your stored data by running :py:mod:`pywws.reprocess` after you change this value. .. versionadded:: 13.10_r1094 ``usb activity margin`` controls the algorithm that avoids the "USB lockup" problem that affects some stations. It sets the number of seconds either side of expected station activity (receiving a reading from outside or logging a reading) that pywws does not get data from the station. If your station is not affected by the USB lockup problem you can set ``usb activity margin`` to 0.0. .. versionadded:: 13.11_r1102 ``gnuplot version`` tells :py:mod:`pywws.plot` and :py:mod:`pywws.windrose` what version of gnuplot is installed on your computer. This allows them to use version-specific features to give improved plot quality. .. versionadded:: 14.01_r1133 ``frequent writes`` tells :py:mod:`pywws.regulartasks` to save weather data and status to file every time there is new logged data. The default is to save the files every hour, to reduce "wear" on solid state memory such as the SD cards used with Raspberry Pi computers. If your weather data directory is stored on a conventional disc drive you can set ``frequent writes`` to ``True``. .. _weather_ini-paths: paths: directories in which templates etc. are stored ----------------------------------------------------- :: [paths] templates = /home/$USER/weather/templates/ graph_templates = /home/$USER/weather/graph_templates/ work = /tmp/weather user_calib = /home/$USER/weather/modules/usercalib modules = /home/$USER/weather/modules/ These entries specify where your text templates and graph templates are stored, where temporary files should be created, where template output (that is not uploaded) should be put, the location of your calibration module (if you have one), and where any other modules you create are stored. live: tasks to be done every 48 seconds --------------------------------------- :: [live] services = ['underground', ('copy', 'yowindow.xml')] text = ['yowindow.xml'] plot = [] This section specifies tasks that are to be carried out for every data sample during 'live logging', i.e. every 48 seconds. ``services`` is a list of 'services' to upload data to. Some are just a single word, others have one or more parameters and need to be enclosed in brackets. Each one listed must have a module in ``pywws.service`` or your modules directory. See :ref:`integration - other services` for more detail. pywws will automatically limit the frequency of service uploads according to each service's requirements. ``text`` and ``plot`` are lists of text and plot templates to be processed. logged: tasks to be done every time the station logs a data record ------------------------------------------------------------------ :: [logged] services = ['underground', 'metoffice'] text = [] plot = [] This section specifies tasks that are to be carried out every time a data record is logged when 'live logging' or every time an hourly cron job is run. ``services`` is a list of 'services' to upload data to. Some are just a single word, others have one or more parameters and need to be enclosed in brackets. Each one listed must have a module in ``pywws.service`` or your modules directory. See :ref:`integration - other services` for more detail. ``text`` and ``plot`` are lists of text and plot templates to be processed. cron: tasks to be done at a particular time or date --------------------------------------------------- .. versionadded:: 14.05.dev1211 :: [cron daily 9] format = 0 9 * * * plot = ['28days.png.xml'] text = ['forecast.txt', 'forecast_9am.txt', 'forecast_week.txt'] services = [('twitter', 'forecast.txt'), ('ftp', 'forecast_9am.txt', 'forecast_week.txt')] [cron daily 21] format = 0 21 * * * text = ['forecast_9am.txt'] services = [('ftp', 'forecast_9am.txt')] plot = [] [cron weekly] format = 0 9 * * 6 plot = ['2008.png.xml', '2009.png.xml', '2010.png.xml', '2011.png.xml', '2012.png.xml', '2013.png.xml'] text = ['2008.txt', '2009.txt', '2010.txt', '2011.txt', '2012.txt', '2013.txt'] services = [('ftp', '2008.png', '2009.png', '2010.png', '2011.png', '2012.png', '2013.png', '2008.txt', '2009.txt', '2010.txt', '2011.txt', '2012.txt', '2013.txt')] ``[cron name]`` sections provide a very flexible way to specify tasks to be done at a particular time and/or date. ``name`` can be anything you like, but each ``[cron name]`` section must have a unique name. To use ``[cron name]`` sections you need to install the "croniter" package. See :doc:`../essentials/dependencies` for more detail. ``format`` specifies when the tasks should be done (in local time), in the usual crontab format. (See ``man 5 crontab`` on any Linux computer.) Processing is not done exactly on the minute, but when the next live or logged data arrives. hourly: tasks to be done every hour ----------------------------------- :: [hourly] services = [('twitter', 'tweet.txt'), ('ftp', '7days.png', '24hrs.png', 'rose_12hrs.png', '24hrs.txt', '6hrs.txt', '7days.txt', 'feed_hourly.xml')] text = ['tweet.txt', '24hrs.txt', '6hrs.txt', '7days.txt', 'feed_hourly.xml'] plot = ['7days.png.xml', '24hrs.png.xml', 'rose_12hrs.png.xml'] This section specifies tasks that are to be carried out every hour when 'live logging' or running an hourly cron job. ``services`` is a list of 'services' to upload data to. Some are just a single word, others have one or more parameters and need to be enclosed in brackets. Each one listed must have a module in ``pywws.service`` or your modules directory. See :ref:`integration - other services` for more detail. ``text`` and ``plot`` are lists of text and plot templates to be processed. 12 hourly: tasks to be done every 12 hours ------------------------------------------ :: [12 hourly] services = [] text = [] plot = [] This section specifies tasks that are to be carried out every 12 hours when 'live logging' or running an hourly cron job. Use it for things that don't change very often, such as monthly graphs. The tasks are done at your day end hour, and 12 hours later. ``services`` is a list of 'services' to upload data to. Some are just a single word, others have one or more parameters and need to be enclosed in brackets. Each one listed must have a module in ``pywws.service`` or your modules directory. See :ref:`integration - other services` for more detail. ``text`` and ``plot`` are lists of text and plot templates to be processed. daily: tasks to be done every 24 hours -------------------------------------- :: [daily] services = [('ftp', '2008.png', '2009.png', '2010.png', '28days.png', 'feed_daily.xml')] text = ['feed_daily.xml'] plot = ['2008.png.xml', '2009.png.xml', '2010.png.xml', '28days.png.xml'] This section specifies tasks that are to be carried out every day when 'live logging' or running an hourly cron job. Use it for things that don't change very often, such as monthly or yearly graphs. The tasks are done at your day end hour. ``services`` is a list of 'services' to upload data to. Some are just a single word, others have one or more parameters and need to be enclosed in brackets. Each one listed must have a module in ``pywws.service`` or your modules directory. See :ref:`integration - other services` for more detail. ``text`` and ``plot`` are lists of text and plot templates to be processed. underground, metoffice, temperaturnu etc: configuration of posting to 'services' -------------------------------------------------------------------------------- :: [underground] station = IXYZABA5 password = secret These sections contain information such as passwords and station IDs needed to upload data to weather services. The names of the data entries depend on the service. The example shown is for Weather Underground. ``station`` is the PWS ID allocated to your weather station by Weather Underground. ``password`` is your Weather Underground password. status.ini - status file format =============================== This file is written by pywws and should not (usually) be edited. The following sections are currently in use: * fixed: values copied from the weather station's "fixed block". * clock: synchronisation information. * last update: date and time of most recent task completions. fixed: values copied from the weather station's "fixed block" ------------------------------------------------------------- :: [fixed] fixed block = {...} ``fixed block`` is all the data stored in the first 256 bytes of the station's memory. This includes maximum and minimum values, alarm threshold settings, display units and so on. clock: synchronisation information ---------------------------------- :: [clock] station = 1360322930.02 sensor = 1360322743.69 These values record the measured times when the station's clock logged some data and when the outside sensors transmitted a new set of data. They are used to try and prevent the USB interface crashing if the computer accesses the weather station at the same time as either of these events, a common problem with many EasyWeather compatible stations. The times are measured every 24 hours to allow for drift in the clocks. last update: date and time of most recent task completions ---------------------------------------------------------- :: [last update] hourly = 2013-05-30 19:04:15 logged = 2013-05-30 19:04:15 daily = 2013-05-30 09:04:15 openweathermap = 2013-05-30 18:59:15 underground = 2013-05-30 18:58:34 metoffice = 2013-05-30 18:59:15 12 hourly = 2013-05-30 09:04:15 These record date & time of the last successful completion of various tasks. They are used to allow unsuccessful tasks (e.g. network failure preventing uploads) to be retried after a few minutes. pywws-24.2.0/src/doc/img_1504.jpg0000644000200200001440000003672113305436026016213 0ustar jimusers00000000000000JFIFC  !"$"$C" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzPhotoshop 3.08BIMIMG_1504i6Elecsa AstroTouch 6975 weather station outdoor sensorst(C) Jim Easterbrookvwww.jim-easterbrook.me.uk ?R7" f<%̫c5h [Ϻ.ۚ$3*Ƴ.bU.EuSLF]̜nk:Awhr̋bZ܂ Qa>!\,3NC1F)Rb1@ b(?bLSIf(?bybv(`R7R hTg `XwNqVf5+d[&Rfebjfd@{Ui5F79t*nQDt9AZ N6V6F rB^O{I5Bpz֤Uw=FDZ[Tbj"9Lևڪےžz =KFbB͸?5 `+*6 ]0C P<)SJu"3^$X跳Fy#8TtM_Fu]WM,phʆ>ǡV 5sI^f)1O"Fb("#!&)1@~(|K4='ZYsU!22ER?UF;`qL,("<ꐊW#{$[ST.0`3L%5;JFI"τ5ކp -S*T)..6ZΖfv4VQ⫲>3oXv$eVQ⇄u7( 7n"'<ʼŷ0k w%gtRԤxPW{shE5ɒ?۶>%:֤&i7.XNN}+Jp>.T?NrkiaeNlT궦{'mtIuw>sHj:Vl,q> s>#.7-J@Tהz>YӠkF4 FVb=8׸auW2E} }yR)8r~>^Ljlcþ'̴~ k0>ESʯ3pZw1]'q{!xS+xF 4Z9^M[h:ί+C:!=?A^yg|%՞h䛧y٥FN6:>9k|iƽtzjOjU"G#t{b8FׁZkѬuMsGWM I#px_^[9,8qty]iG!bυRj/qf;Xtl )D GJrB~2RDxiMޮ/cEqGQYՇWB*妬GyA1EH5b*kf3I9TbUh0g] ްAL5{;CSޚ=+>}9+'l]U>[vԤsĐzaթxwQѣ(ȻIkpEj vN2QzI5żpS-=؂sN*qu#Z:tC/til53]YaU@z7+]bO@XeYeu'eQErm䓭%IklDFc8l4+k-P?:꧃Zj~mT qrfMy1T5\.Dz3H˔,9c[AO4 l e(m[sͩ=6FmWZmvk@;Uި1Cv?Z1ޜ!X.p0,^Wa`#iB$6DzI(aJu~SS>y#_V{*fmUWɌp> y'4fObB+VW+h>j:I긮YFLqdT%f0, Vn^Ǖ4T2È-GճEj4zm8I;^չfE "mpOqZ}LetQMANZE.R~I5o%zJsj;e w 6'',OT{Hq7[l>M-;DU%Okô7 ZԪ|}mت(70g?Q\5+p QKBm[{TOKFNNOk6IDQk vϩf'ޡ9D78bi-!~\ꩍu[6Vo"7~hɪ\\1rsVƋ~bb@'-E'zʥZ֫KG;}Nʮ eq&a`nLav>I&VCu'~{>D5Ti/s2qQ͟MVe! oT:u.z1ZIR# wmJdž6΍ĪVTUڽΡ Bi 5v!L&+0qrGx)fTP c ޹[]&c66p/ʹXPe9^r3zcyCJ NiVCV(H? *!JhqE'bWXj1aO MFmw֭GwֹޮC83\oW&ʆlLY  RZ]1H?=N?#5z$a]J|KvΰcTj"yX?CzbӨ]k8VRQMJ дk{赉thrm>5Xa"wߩwzޟp)hPJ %(=7Zp4 \XXKcXĖv抚$V *PXMƟ0;G]VG,4bSHRTqH€E8 1@ m-.(%(LS@?O>?Zlj6w"vSo5G+~#_' =,G>fm[>}ߴ+7~cZѲx'9vd]><:+\gfsQ\cJ t%m hR@^i8ƋkF݁k27*Ϸa82QYqcXlMW MWª]qz@RTI&*KkKmo49+?R-:gFy0=9⸱XAi:haWH1ʍAuFEcop yц#Eq 4l6Z祛Sm<x-ZSke}J1}|5jZnb,-h:)קW9ќ>$SQJ1N)F(=(`xv'gNvΦ?aMyXJWϑ\cgQ R5txW쒍ڔ;c==cݯ㣣r D JZ(q,Z)R\Є⬋p5V h7Y:U#3Z V^G?Ϳ.vr$6yS$Kҽoir ٬cX|Vm5TS@$r >vP+17Sn!soQsZW#W 2^ˊ~ Xߩԧ>LHexeBF]OPA\WYR5ǚU;;Z }5)H)GRq4B8v'bHn{?ʴ>%_'PNϼkY_'@!ZDfi#Bb^~s^,**uDRPse<;in+gd '\r\+wc&ۥœԞԦ:=G?ZfWAbPRSI@ Eab)ޫS4MIG3Rjoc %%mgFJ4IҒsH"W]^ܘg› <{z5LZ\-;fڠbHjWe ׶5aӱHEP Hihu!(e$S,isRDEY~0E{CrWح -)J=떴=Szr䒑?fTDhzHkyg$aD;:KEѯ}*?_U bWke5zqS{q]˷jmJ軣#Ƨ s+VZ夫9܁5ӃEsdH8n #ls^|NՎUfJ$5k1fU?U5Q7ZzIӏWvKKj\TSuf*xBoSxc^R=M/tϳ/8+ӴZBMX3QWo-gHTs2ixRĚgX!aMl pT4>x#u;WֺSĺ4EëIܙ`ǚ$6<ZfkZ.eYUnpTikpѭxQG>@kиx㤖6 tMRL\//Y%UfS3 Ww);+QqcI "*9bX dPejZ#6!4 (4Pժx)bL| sz@jTFrusR+USQ`;EV)"A5<Û0+\GsQ6?Jƺ汖9J1l5[,T6꧍<F%[nHfEGрzkC]XhN70OP:W@Tt9""h(GpGzjӎScDHD1j3oov[m0jMO>r`R7Gr+W̭ѯbKd#C ֦ooq??B;FZi{B[JA.c*+.kkI`ݾIH瓎1ڹM?h~y|9'XJ84y r_kwO!e>hwګ"w]NGO35xŗ~%]NR@6m'P*?Z^xv\ uiqU W+c +4B"tf`A N1ְu\59t&ueEU_@gz~%qMPz\kJ>T~95c ;f=i٦HMIKHiRZCH)M%(NN-- QKIK@4 ձLNG4ep6Z2Yg.iU)~>cyemw~CQOt򵤥RMwc !42)JJCKI@ IKHh ) ZAK@ťP!–Rœ)RQ(EV$->Htg5_Qa<ʥFTU%U?zmaYjR׵FFׅ>hİMpȯ1yEޡ]d ׊ _ tbmKZOG 3df^Gs}ɍ)>Zd'lgm2hTVUʵ;bs['h>*K+WTsج?`ԟD՗tAcዿZﳿRѮTn"#n8ǧ#G׏hM@< 6r M:aPAu|[_WK4gQ%كl/$@5WMzy7CRy>27ii: WKJ?|hԖdfke UYu<`Ere'k捖֑,S &eZ]fvbRRуNX)jBjy|IL299ySMIc,cG0r*?-C4SqMU JZ@-- \IK@Ţ7҈,晆B!b? )cŽ+:Y4ZHcY큚zب+hyĚv=]mJ"Q W[47ߊcR>U_#?0mrVL-eDl =s5 A^֯[r #H_3"ze>o`$9lu}oB4mؑN"P?30[fOMv.3_ƹeDdH/xBͼ=X}6ZXn;󏊾 .4{׳X@%qs^ NsҽOeİ8ɕs*=Ki<3{f/ rHV{5-];'; -܋fiL C=Ư{j_.K2V[D#=GIql?.ywm'SQRCnmw^U;ō #-ҩ]jGk:&Ixn{{{fS8>;V#J.J]F,V >kQZ})̯Bn׵vGAuOe_í{լqn!]AWdtus*\T]wG, M%{yϸ( *QE%)Vhn_F~l͟җ}fJjy\ҥfR~"[n4Okr?,Qw,gf{bf E: K@sfBW_z){5x=u)ݴe}TNz]"և֖>u Im%GG}ܟ=!H'KG(sAҋݸ+Zc?J[g",QùQBcڦ\Io"IHo*e솛m\zOM;D;|AbA¾ 5 @1ʹד×4Ȍ#?a2O^5 : zGg&"O>;c,!Mۓ⴮<)oömƠ(k;( =3;u8~xk_xcI Uʥպ>k\ J[X_6CHr\#mK$O;?㮀|E,!R$Wr GQ~0<}fWaǓwv6y#=~xT]Υ4VAkl5ږ3em,xm&;c Gd({W|$N˕qUߌ |vWvi) c &O&qI'{}+_TxغJ񤥤>tJCKHh))M%QE0)š)hRh )iPfO6$oRNMY;j7GẍAUFAOa :d}A Ί2Z6z\. X8%E`d &:&>'ٮd"1]}а#~op&"9#?+χ VM6pUON7zg¯X_ww5&w}se5* Uo\ό-;Uդuiol.~hvkԭ,C-\#ʿl:hl񆟨FK$>j2vڸo 펤l{^$4njס(5)$VM:#Mt&wRX g?qMIt7{%IiӮcPkw O\XĚ}(dTnOeF6=xmݣ~%ohsm@"w~xV|3qOX@dׯ"$ZHE޶)n9=8E8q\m#ޭե.^fJ˩<(&˕¾ fg+~Kw`97asGخDd/uiL/S#?@.iaoʤGw_=l?U -^;i!І/9ǵ}%ᯋdӵ&xndk[a(ȯkFH.z/xk]eG;u_4kj{7,4Iu9u+^MFiʉW~Xt[ nmDHp d3T岉DdXAW G*x$ZOHQ\娑i$.ѷ'RTa˱^nZ7(S$+*6 1ۜjwTdY+^^2d1tn|zb2ks:q6gDʡ$c=ӑZpVlsVDmqR,+ +u"!̑I'B`pjo܂y?Y)Lϯm{7Q;WE;]@\O\h1E]S;.F)i5IBIKHJ(h4PM.WqP #튖j-4Vdw0;gM6ڒM3z$d2ю_y{E%-y*+P-W  k6/Zv-W w$d :_}SK-a.4oy]P=*y/^P+4FFp7Buk}ᶷT]B+{fx7%pU#fXXJ0z,,MA|<5+m {X68D v G/5 <9o&:tOkφ%f,R ) =ЊӬciM>)dADH@#8՗*V9Kz޿ߛ'v|3I[d`O9 nU/7C.'sfX>?$ *\RB!hW)$x!eHp?.;tFĨzuktK67K5 {2H<m?M+eY@~B ӷj)ngkG!:q& Έv Y9'[S~h˒r?:Do\o|w*IT$Z@0A"ZRF)YA#'d1"/2v4Cy@P:UV8lvǽ0D+pTK)2A#B@cEK"WnEPpywws-24.2.0/src/doc/index.rst0000644000200200001440000000522113305436032016111 0ustar jimusers00000000000000.. pywws - Python software for USB Wireless Weather Stations http://github.com/jim-easterbrook/pywws Copyright (C) 2008-18 pywws contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. .. image:: img_1504.jpg :align: right .. include:: ../../README.rst :end-before: I have written Documentation is available in the following languages (the non-English versions are not complete or up to date): * `English `_ * `Français `_ -- translated by Jacques Desroches * `Italiano `_ -- translated by Edoardo .. include:: ../../README.rst :start-after: http://pywws.readthedocs.io/ :end-before: Credits Documentation for the legacy version is also available on Read the Docs: http://pywws.readthedocs.io/en/legacy/ Installing and upgrading pywws ============================== pywws can be installed directly from the `Python Package Index`_ (PyPI) using the pip_ command. See :doc:`guides/getstarted` for full instructions. Documentation ============= Documentation is included with pywws downloads, and is also available `online `_. A good starting place is :doc:`guides/getstarted` which describes in more detail how to install pywws. If you have questions not answered in the documentation, please join the `pywws Google mailing list / discussion group `_ and ask there. Note that your first message to the group will not appear immediately -- new posters have to be approved by a moderator, to prevent spam messages. Contents -------- .. toctree:: :maxdepth: 2 Dependencies User guides Python modules Licence pywws Contributors Change log Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` .. include:: ../../README.rst :start-after: placeholder-credits pywws-24.2.0/src/doc/pywws_logo.ico0000644000200200001440000000257613305436026017172 0ustar jimusers00000000000000h( mh{8Vs<';OShVѹtUɼv<Apâx%tC>\\\\\\_88F"\\\\\\\\\\"U 5\\\\\\\\\"""4M"""\\\\\"m 3SY "\\^G7L*? nv7R "\o@\\J ViZ\\\\/^\\\saTk\\\#r\B<\\\eA:\\\\=+"]"\\\\\""W#2q.c)"\\\"+Eu\"$l6>\\\;C""\\\[X -jKNP0%\\\\\tf`!1(Q#\\\\\\"9bOI,dg2\\\\\\\"hD&w2\\\\\\\\\\'Hp\\\\\\\\pywws-24.2.0/src/doc/pywws_logo.png0000644000200200001440000001107113305436026017172 0ustar jimusers00000000000000PNG  IHDR?7 sBIT|dIDATh՚y\E?U޾==Kf0 1DB ( 7@>}1OdQDP"K`BȞd^RUd&a >svuU)vD"ǂB)vu]:s`45f"nk[{yÁ Lh4sBM"tE V0xQNӈo՚BѨQixuIe,pD4Dlul5(k\߅ T5HgZri֬D).8pUHxh>_3r.驿WJJx'T3&}4]V裔U KE|oUHnwb{M`wȬT6KͼE,~0qGcVcJDZUEG6L_FĠun oT  WD(Ɔuqe  U8ӃsQJ=R~$x^;[6_NG ͧ!.E|]oD خS@qqqs)泱׊HJ.<2|R*NR݌=KMEh] <@O9E:yAJ;NiIJ)P  %<Ǔ&/U5hi; 7("?q(["8RהnEu!I >G@k%4@Jy9T-l^ Owׇ)q<<om0j|<%@:'CKzwPܞJ?>:ԁQ{ tw}~ 8uklC~i6R' |֯Ńxi/ٴq1at>>Y810 )h7enn"R<ֽJCsI$?:k.$Ή557\cX OK80&O91c&ʬZg;=z8%Ӧ$ygIF~s=JT*1 ̧iIS ˸7s)8|U ?8YT^m(S.͛.#B5' i9]ȍ\M(%rÛpd%"OkG~g~ٷy.[|q}@MR]_i0qOkZ\tw[|>zj7Ok[] VXͿ$IvJS|J@R1fǦ͛ߵ?o fonʢ1 8838QcIA8& #WIEhiiii8~Ή~Isc \.@P[ds _'艱Lzӱ:n6G:)CV`J)ra13? ֯[=w#DTT#|_5[h J$Ē$ T?@9f@1}FE )"ơSFiG؍[eX$ Cig)0ܶ1\28OrǰGg'R}Q՚BsRN}Ǐe4Z8,R 4] P@YiXgz>^"Y1cfNvɷsL~pA$q\:RVZW8ķ/1i}<Ё$F`<00 VP N#9sΑ$ ʣ?ygn}ISjaraHE|S:N×. 8ОK:,gc=C9hwal(qԄ*`b$`b/h1{AS;qeyP-NY]Ð|>O$\z7ڛ~10SZ0'c9׿~|0'<߯'A. 9aXPwqb"PZ¥1n"4; :NhvjmN~33*v=$B=Ox+J([ñU{x} kj=ؓk d"ʫk~rK]e`;jJ2 lq \^ߋ3$IDY`2)(̬qA5Ʌ̓nͿ.,h4'k Nj- xCkOiƌ_%̾IMM-1Ƥ^_/Q}ϯE|፹[j*"8L; B(J]l3uv0{y^3<D UIENDB`pywws-24.2.0/src/doc/requirements.txt0000644000200200001440000000004614556653422017551 0ustar jimusers00000000000000sphinx==5.3.0 sphinx_rtd_theme==1.3.0 pywws-24.2.0/src/pywws/0000755000200200001440000000000014556655656014724 5ustar jimusers00000000000000pywws-24.2.0/src/pywws/__init__.py0000644000200200001440000000007514556655540017027 0ustar jimusers00000000000000__version__ = '24.2.0' _release = '1709' _commit = '8444adb' pywws-24.2.0/src/pywws/calib.py0000644000200200001440000001233213357605510016327 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-18 pywws contributors # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """ Calibrate raw weather station data This module allows adjustment of raw data from the weather station as part of the 'processing' step (see :doc:`pywws.process`). For example, if you have fitted a funnel to double your rain gauge's collection area, you can write a calibration routine to double the rain value. The default calibration generates the relative atmospheric pressure. Any user calibration you write must also do this. Writing your calibration module ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Firstly, decide where you want to keep your module. Like your text and graph templates, it's best to keep it separate from the pywws code, so it isn't affected by pywws upgrades. I suggest creating a ``modules`` directory in the same place as your ``templates`` directory. You could start by copying one of the example calibration modules, or you can create a plain text file in your ``modules`` directory, e.g. ``calib.py`` and copy the following text into it: .. code-block:: python3 class Calib(object): def __init__(self, params, stored_data): self.pressure_offset = float(params.get('config', 'pressure offset')) def calib(self, raw): result = dict(raw) # calculate relative pressure result['rel_pressure'] = result['abs_pressure'] + self.pressure_offset return result The :class:`Calib` class has two methods. :py:meth:`Calib.__init__` is the constructor and is a good place to set any constants you need. It is passed a reference to the raw data storage which can be useful for advanced tasks such as spike removal. :py:meth:`Calib.calib` generates a single set of 'calibrated' data from a single set of 'raw' data. There are a few rules to follow when writing this method: - Make sure you include the line ``result = dict(raw)``, which copies all the raw data to your result value, at the start. - Don't modify any of the raw data. - Make sure you set ``result['rel_pressure']``. - Don't forget to ``return`` the result at the end. When you've finished writing your calibration module you can get pywws to use it by putting its location in your ``weather.ini`` file. It goes in the ``[paths]`` section, as shown in the example below:: [paths] work = /tmp/weather templates = /home/jim/weather/templates/ graph_templates = /home/jim/weather/graph_templates/ user_calib = /home/jim/weather/modules/usercalib Note that the ``user_calib`` value need not include the ``.py`` at the end of the file name. """ __docformat__ = "restructuredtext en" import importlib import logging import os import sys logger = logging.getLogger(__name__) class DefaultCalib(object): """Default calibration class. This class sets the relative pressure, using a pressure offset originally read from the weather station. This is the bare minimum 'calibration' required. """ def __init__(self, params, stored_data): self.pressure_offset = float(params.get('config', 'pressure offset')) def calib(self, raw): result = dict(raw) # calculate relative pressure result['rel_pressure'] = result['abs_pressure'] + self.pressure_offset return result usercalib = None class Calib(object): """Calibration class that implements default or user calibration. Other pywws modules use this method to create a calibration object. The constructor creates either a default calibration object or a user calibration object, depending on the ``user_calib`` value in the ``[paths]`` section of the ``params`` parameter. It then adopts the calibration object's :py:meth:`calib` method as its own. """ calibrator = None def __init__(self, params, stored_data): global usercalib if not Calib.calibrator: user_module = params.get('paths', 'user_calib', None) if user_module: logger.info('Using user calibration') path, module = os.path.split(user_module) sys.path.insert(0, path) module = os.path.splitext(module)[0] usercalib = importlib.import_module(module) del sys.path[0] Calib.calibrator = usercalib.Calib(params, stored_data) else: logger.info('Using default calibration') Calib.calibrator = DefaultCalib(params, stored_data) self.calib = Calib.calibrator.calib pywws-24.2.0/src/pywws/constants.py0000644000200200001440000000241713305436026017271 0ustar jimusers00000000000000#!/usr/bin/env python # pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-15 pywws contributors # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """Bits of data used in several places. This module collects together some 'constants' that are used in other pywws modules. """ __docformat__ = "restructuredtext en" from datetime import timedelta SECOND = timedelta(seconds=1) HOUR = timedelta(hours=1) DAY = timedelta(hours=24) class Twitter(object): consumer_key = '62moSmU9ERTs0LK0g2xHAg' consumer_secret = 'ygdXpjr0rDagU3dqULPqXF8GFgUOD6zYDapoHAH9ck' pywws-24.2.0/src/pywws/conversions.py0000644000200200001440000002266613351134756017643 0ustar jimusers00000000000000#!/usr/bin/env python # pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-18 pywws contributors # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """conversions.py - a set of functions to convert pywws native units (Centigrade, mm, m/s, hPa) to other popular units """ from __future__ import absolute_import, print_function __docformat__ = "restructuredtext en" import math import pywws.localisation import pywws.process def scale(value, factor): """Multiply value by factor, allowing for None values.""" if value is None: return None return value * factor def illuminance_wm2(lux): "Approximate conversion of illuminance in lux to solar radiation in W/m2" return scale(lux, 0.005) def pressure_inhg(hPa): "Convert pressure from hectopascals/millibar to inches of mercury" return scale(hPa, 1 / 33.86389) def pressure_trend_text(trend): """Convert pressure trend to a string, as used by the UK met office. """ _ = pywws.localisation.translation.ugettext if trend > 6.0: return _(u'rising very rapidly') elif trend > 3.5: return _(u'rising quickly') elif trend > 1.5: return _(u'rising') elif trend >= 0.1: return _(u'rising slowly') elif trend < -6.0: return _(u'falling very rapidly') elif trend < -3.5: return _(u'falling quickly') elif trend < -1.5: return _(u'falling') elif trend <= -0.1: return _(u'falling slowly') return _(u'steady') def rain_inch(mm): "Convert rainfall from millimetres to inches" return scale(mm, 1 / 25.4) def temp_f(c): "Convert temperature from Celsius to Fahrenheit" if c is None: return None return (c * 9.0 / 5.0) + 32.0 def winddir_average(data, threshold, min_count, decay=1.0): """Compute average wind direction (in degrees) for a slice of data. The wind speed and direction of each data item is converted to a vector before averaging, so the result reflects the dominant wind direction during the time period covered by the data. Setting the ``decay`` parameter converts the filter from a simple averager to one where the most recent sample carries the highest weight, and earlier samples have a lower weight according to how long ago they were. This process is an approximation of "exponential smoothing". See `Wikipedia `_ for a detailed discussion. The parameter ``decay`` corresponds to the value ``(1 - alpha)`` in the Wikipedia description. Because the weather data being smoothed may not be at regular intervals this parameter is the decay over 5 minutes. Weather data at other intervals will have its weight scaled accordingly. :note: The return value is in degrees, not the 0..15 range used elsewhere in pywws. :param data: a slice of pywws raw/calib or hourly data. :type data: pywws.storage.CoreStore :param threshold: minimum average windspeed for there to be a valid wind direction. :type threshold: float :param min_count: minimum number of data items for there to be a valid wind direction. :type min_count: int :param decay: filter coefficient decay rate. :type decay: float :rtype: float """ wind_filter = pywws.process.WindFilter() count = 0 for item in data: wind_filter.add(item) if item['wind_dir'] is not None: count += 1 if count < min_count: return None speed, direction = wind_filter.result() if speed is None or speed < threshold: return None return direction * 22.5 def winddir_degrees(pts): "Convert wind direction from 0..15 to degrees" return scale(pts, 22.5) _winddir_text_array = None def winddir_text(pts): "Convert wind direction from 0..15 to compass point text" global _winddir_text_array if pts is None: return None if not isinstance(pts, int): pts = int(pts + 0.5) % 16 if not _winddir_text_array: _ = pywws.localisation.translation.ugettext _winddir_text_array = ( _(u'N'), _(u'NNE'), _(u'NE'), _(u'ENE'), _(u'E'), _(u'ESE'), _(u'SE'), _(u'SSE'), _(u'S'), _(u'SSW'), _(u'SW'), _(u'WSW'), _(u'W'), _(u'WNW'), _(u'NW'), _(u'NNW'), ) return _winddir_text_array[pts] def wind_kmph(ms): "Convert wind from metres per second to kilometres per hour" return scale(ms, 3.6) def wind_mph(ms): "Convert wind from metres per second to miles per hour" return scale(ms, 3.6 / 1.609344) def wind_kn(ms): "Convert wind from metres per second to knots" return scale(ms, 3.6 / 1.852) _bft_threshold = ( 0.3, 1.5, 3.4, 5.4, 7.9, 10.7, 13.8, 17.1, 20.7, 24.4, 28.4, 32.6) def wind_bft(ms): "Convert wind from metres per second to Beaufort scale" if ms is None: return None for bft in range(len(_bft_threshold)): if ms < _bft_threshold[bft]: return bft return len(_bft_threshold) def dew_point(temp, hum): """Compute dew point, using formula from http://en.wikipedia.org/wiki/Dew_point. """ if temp is None or hum is None: return None a = 17.27 b = 237.7 gamma = ((a * temp) / (b + temp)) + math.log(float(hum) / 100.0) return (b * gamma) / (a - gamma) def cadhumidex(temp, humidity): "Calculate Humidity Index as per Canadian Weather Standards" if temp is None or humidity is None: return None # Formulas are adapted to not use e^(...) with no appreciable # change in accuracy (0.0227%) saturation_pressure = (6.112 * (10.0**(7.5 * temp / (237.7 + temp))) * float(humidity) / 100.0) return temp + (0.555 * (saturation_pressure - 10.0)) def usaheatindex(temp, humidity, dew=None): """Calculate Heat Index as per USA National Weather Service Standards See http://en.wikipedia.org/wiki/Heat_index, formula 1. The formula is not valid for T < 26.7C, Dew Point < 12C, or RH < 40% """ if temp is None or humidity is None: return None if dew is None: dew = dew_point(temp, humidity) if temp < 26.7 or humidity < 40 or dew < 12.0: return temp T = (temp * 1.8) + 32.0 R = humidity c_1 = -42.379 c_2 = 2.04901523 c_3 = 10.14333127 c_4 = -0.22475541 c_5 = -0.00683783 c_6 = -0.05481717 c_7 = 0.00122874 c_8 = 0.00085282 c_9 = -0.00000199 return ((c_1 + (c_2 * T) + (c_3 * R) + (c_4 * T * R) + (c_5 * (T**2)) + (c_6 * (R**2)) + (c_7 * (T**2) * R) + (c_8 * T * (R**2)) + (c_9 * (T**2) * (R**2))) - 32.0) / 1.8 def wind_chill(temp, wind): """Compute wind chill, using formula from http://en.wikipedia.org/wiki/wind_chill """ if temp is None or wind is None: return None wind_kph = wind * 3.6 if wind_kph <= 4.8 or temp > 10.0: return temp return min(13.12 + (temp * 0.6215) + (((0.3965 * temp) - 11.37) * (wind_kph ** 0.16)), temp) def apparent_temp(temp, rh, wind): """Compute apparent temperature (real feel), using formula from http://www.bom.gov.au/info/thermal_stress/ """ if temp is None or rh is None or wind is None: return None vap_press = (float(rh) / 100.0) * 6.105 * math.exp( 17.27 * temp / (237.7 + temp)) return temp + (0.33 * vap_press) - (0.70 * wind) - 4.00 def cloud_base(temp, hum): """Calculate cumulus cloud base in metres, using formula from https://en.wikipedia.org/wiki/Cloud_base or https://de.wikipedia.org/wiki/Kondensationsniveau#Konvektionskondensationsniveau """ if temp is None or hum is None: return None dew_pt = dew_point(temp, hum) spread = float(temp) - dew_pt return spread * 125.0 def cloud_ft(m): "Convert cloud base from metres to feet." return scale(m, 3.28084) def _main(argv=None): global _winddir_text_array # run some simple tests print('Wind speed:') print('%6s %8s %8s %8s %6s' % ('m/s', 'km/h', 'mph', 'knots', 'bft')) for ms in (0, 1, 2, 4, 6, 9, 12, 15, 18, 22, 26, 30, 34): print('%6g %8.3f %8.3f %8.3f %6d' % ( ms, wind_kmph(ms), wind_mph(ms), wind_kn(ms), wind_bft(ms))) print('Wind direction:') for pts in range(16): print(' ' + winddir_text(pts), end='') print('') print('Wind direction, in Swedish:') pywws.localisation.set_translation('sv') _winddir_text_array = None for pts in range(16): print(' ' + winddir_text(pts), end='') print('') print('Cloud base in m and ft:') for hum in range(25, 75, 5): print("%8.3f m / %8.3f ft" % (cloud_base(15.0, hum), cloud_ft(cloud_base(15.0, hum)))) print('') if __name__ == "__main__": _main() pywws-24.2.0/src/pywws/datastoretransfer.py0000644000200200001440000001025714221250641021004 0ustar jimusers00000000000000""" This module transfers and converts the pywws weather station data from one data format and directory to another. Usage: python -m pywws.datastoretransfer SOURCE_TYPE SOURCE_DIR SINK_TYPE SINK_DIR Example: python -m pywws.datastoretransfer filedata c:\weather_data sqlite3data d:\weather This can be used to convert from the default file base storage system to an SQL based sorage system, or back. The transfer will overwrite existing data in place which may leave existing data in the destination if the incoming data does not overlap (i.e. source data is newer than the destination). This is a risky way to merge datastores together. Otherwise, its recommended to use the optional -c argument to ensure the destination is cleared first. You may choose the same storage module for both source and destination with different directories, and this is the equivalent of simply copying the data but will build the underlying files from scratch. However, copying the files by hand is likely to be faster. Config files such as weather.ini, and folders such as templates etc. are not copied, so please ensure you consider seperately if required. """ from __future__ import absolute_import, print_function import argparse import importlib import logging import pywws.logger logger = logging.getLogger(__name__) pywws.logger.setup_handler(1) def monitor(i): """Given an iterator, yields data from it but prints progress every 10,000 records""" count = 0 for x in i: count+=1 if count % 10000 == 0: logger.info("%d records so far, current record is %s", count, x["idx"]) yield x if __name__ == "__main__": parser = argparse.ArgumentParser( description="""Copy pywws data from one storage system to another. You must specify the pywws data module, and the path for both the source data set, and the destination data set.""") parser.add_argument("-c", help="Clear the existing destination datastore before transfer", action="store_true", dest="clearfirst") parser.add_argument("SourceType", help="The source storage system type") parser.add_argument("SourceDir", help="The source directory") parser.add_argument("SinkType", help="The destination storage system type") parser.add_argument("SinkDir", help="The destination directory") args = parser.parse_args() source_type = args.SourceType sink_type = args.SinkType source_dir = args.SourceDir sink_dir = args.SinkDir clearfirst=args.clearfirst if source_type == sink_type and source_dir == sink_dir: raise ValueError("You have specified the same source and sink") Source = importlib.import_module("."+source_type, package="pywws") Sink = importlib.import_module("."+sink_type, package="pywws") RawSink = Sink.RawStore(sink_dir) if clearfirst: logger.info("Clearing destination Raw Data...") RawSink.clear() logger.info("Transfering Raw Data...") RawSink.update(monitor(Source.RawStore(source_dir))) RawSink.flush() CalibSink = Sink.CalibStore(sink_dir) if clearfirst: logger.info("Clearing destination Calibrated Data...") CalibSink.clear() logger.info("Transfering Calibrated Data...") CalibSink.update(monitor(Source.CalibStore(source_dir))) CalibSink.flush() HourlySink = Sink.HourlyStore(sink_dir) if clearfirst: logger.info("Clearing destination Hourly Data...") HourlySink.clear() logger.info("Transfering Hourly Data...") HourlySink.update(monitor(Source.HourlyStore(source_dir))) HourlySink.flush() DailySink = Sink.DailyStore(sink_dir) if clearfirst: logger.info("Clearing destination Daily Data...") DailySink.clear() logger.info("Transfering Daily Data...") DailySink.update(monitor(Source.DailyStore(source_dir))) DailySink.flush() MonthlySink = Sink.MonthlyStore(sink_dir) if clearfirst: logger.info("Clearing destination Monthly Data...") MonthlySink.clear() logger.info("Transfering Monthly Data...") MonthlySink.update(monitor(Source.MonthlyStore(source_dir))) MonthlySink.flush() logger.info("Done!")pywws-24.2.0/src/pywws/device_ctypes_hidapi.py0000644000200200001440000001176514221250641021422 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-20 pywws contributors # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """Low level USB interface to weather station, using ctypes to access hidapi. Introduction ============ This module handles low level communication with the weather station via `ctypes `_ and the `hidapi `_ library. It is one of several USB device modules, each of which uses a different USB library interface. See :ref:`Installation - USB library` for details. Testing ======= Run :py:mod:`pywws.testweatherstation` with increased verbosity so it reports which USB device access module is being used:: python -m pywws.testweatherstation -vv 18:10:27:pywws.WeatherStation.CUSBDrive:using pywws.device_ctypes_hidapi 0000 55 aa ff ff ff ff ff ff ff ff ff ff ff ff ff ff 05 20 01 51 11 00 00 00 81 00 00 07 01 00 d0 56 0020 61 1c 61 1c 00 00 00 00 00 00 00 12 02 14 18 09 41 23 c8 00 32 80 47 2d 2c 01 2c 81 5e 01 1e 80 0040 a0 00 c8 80 a0 28 80 25 a0 28 80 25 03 36 00 05 6b 00 00 0a 00 f4 01 18 00 00 00 00 00 00 00 00 0060 00 00 54 1c 63 0a 2f 01 71 00 7a 01 59 80 7a 01 59 80 e4 00 f5 ff 69 54 00 00 fe ff 00 00 b3 01 0080 0c 02 d0 ff d3 ff 5a 24 d2 24 dc 17 00 11 09 06 15 40 10 03 07 22 18 10 08 11 08 30 11 03 07 12 00a0 36 08 07 24 17 17 11 02 28 10 10 09 06 30 14 29 12 02 11 06 57 09 06 30 14 29 12 02 11 06 57 08 00c0 08 31 14 30 12 02 14 18 04 12 02 01 10 12 11 09 13 17 19 11 08 21 16 53 11 09 13 17 19 12 01 18 00e0 07 17 10 02 22 11 06 11 11 06 13 12 11 11 06 13 12 11 11 10 11 38 11 11 10 11 38 10 02 22 14 43 API === """ __docformat__ = "restructuredtext en" import ctypes from ctypes.util import find_library import sys if 'sphinx' in sys.modules: # building documentation, don't need to import hidapi pass else: # open hidapi shared library path = find_library('hidapi') if not path: path = find_library('hidapi-libusb') if not path: path = find_library('hidapi-hidraw') if not path: raise ImportError('Cannot find hidapi library') hidapi = ctypes.CDLL(path) hidapi.hid_open.argtypes = [ ctypes.c_ushort, ctypes.c_ushort, ctypes.c_wchar_p] hidapi.hid_open.restype = ctypes.c_void_p hidapi.hid_read_timeout.argtypes = [ ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t, ctypes.c_int] hidapi.hid_write.argtypes = [ ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t] class USBDevice(object): """Low level USB device access via hidapi library. :param idVendor: the USB "vendor ID" number, for example 0x1941. :type idVendor: int :param idProduct: the USB "product ID" number, for example 0x8021. :type idProduct: int """ def __init__(self, vendor_id, product_id): self.device = hidapi.hid_open(vendor_id, product_id, None) if not self.device: raise IOError("Weather station device not found") # flush any unread input try: self.read_data(32) except IOError: pass def read_data(self, size): """Receive data from the device. If the read fails for any reason, an :obj:`IOError` exception is raised. :param size: the number of bytes to read. :type size: int :return: the data received. :rtype: list(int) """ result = list() data = ctypes.create_string_buffer(8) while size > 0: length = min(size, 8) n = hidapi.hid_read_timeout(self.device, data, length, 100) if n <= 0: raise IOError( 'pywws.device_ctypes_hidapi.USBDevice.read_data failed') for i in range(n): result.append(ord(data[i])) size -= n return result def write_data(self, buf): """Send data to the device. :param buf: the data to send. :type buf: list(int) :return: success status. :rtype: bool """ data = bytes(buf) size = len(data) if hidapi.hid_write(self.device, ctypes.c_char_p(data), size) != size: raise IOError( 'pywws.device_ctypes_hidapi.USBDevice.write_data failed') return True pywws-24.2.0/src/pywws/device_cython_hidapi.py0000644000200200001440000001034314221250641021406 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-20 pywws contributors # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """Low level USB interface to weather station, using cython-hidapi. Introduction ============ This module handles low level communication with the weather station via the `cython-hidapi `_ library. It is one of several USB device modules, each of which uses a different USB library interface. See :ref:`Installation - USB library` for details. Testing ======= Run :py:mod:`pywws.testweatherstation` with increased verbosity so it reports which USB device access module is being used:: python -m pywws.testweatherstation -vv 18:10:27:pywws.weatherstation.CUSBDrive:using pywws.device_cython_hidapi 0000 55 aa ff ff ff ff ff ff ff ff ff ff ff ff ff ff 05 20 01 51 11 00 00 00 81 00 00 07 01 00 d0 56 0020 61 1c 61 1c 00 00 00 00 00 00 00 12 02 14 18 09 41 23 c8 00 32 80 47 2d 2c 01 2c 81 5e 01 1e 80 0040 a0 00 c8 80 a0 28 80 25 a0 28 80 25 03 36 00 05 6b 00 00 0a 00 f4 01 18 00 00 00 00 00 00 00 00 0060 00 00 54 1c 63 0a 2f 01 71 00 7a 01 59 80 7a 01 59 80 e4 00 f5 ff 69 54 00 00 fe ff 00 00 b3 01 0080 0c 02 d0 ff d3 ff 5a 24 d2 24 dc 17 00 11 09 06 15 40 10 03 07 22 18 10 08 11 08 30 11 03 07 12 00a0 36 08 07 24 17 17 11 02 28 10 10 09 06 30 14 29 12 02 11 06 57 09 06 30 14 29 12 02 11 06 57 08 00c0 08 31 14 30 12 02 14 18 04 12 02 01 10 12 11 09 13 17 19 11 08 21 16 53 11 09 13 17 19 12 01 18 00e0 07 17 10 02 22 11 06 11 11 06 13 12 11 11 06 13 12 11 11 10 11 38 11 11 10 11 38 10 02 22 14 43 API === """ __docformat__ = "restructuredtext en" from contextlib import contextmanager import hid class USBDevice(object): """Low level USB device access via cython-hidapi library. :param idVendor: the USB "vendor ID" number, for example 0x1941. :type idVendor: int :param idProduct: the USB "product ID" number, for example 0x8021. :type idProduct: int """ def __init__(self, idVendor, idProduct): if not hid.enumerate(idVendor, idProduct): raise IOError("No weather station connected") self.idVendor = idVendor self.idProduct = idProduct self.hid = hid.device(idVendor, idProduct) @contextmanager def open(self): try: self.hid.open(self.idVendor, self.idProduct) yield finally: self.hid.close() def read_data(self, size): """Receive data from the device. If the read fails for any reason, an :obj:`IOError` exception is raised. :param size: the number of bytes to read. :type size: int :return: the data received. :rtype: list(int) """ result = list() with self.open(): while size > 0: count = min(size, 8) buf = self.hid.read(count) if len(buf) < count: raise IOError( 'pywws.device_cython_hidapi.USBDevice.read_data failed') result += buf size -= count return result def write_data(self, buf): """Send data to the device. :param buf: the data to send. :type buf: list(int) :return: success status. :rtype: bool """ with self.open(): if self.hid.write(buf) != len(buf): raise IOError( 'pywws.device_cython_hidapi.USBDevice.write_data failed') return True pywws-24.2.0/src/pywws/device_libusb1.py0000644000200200001440000001134713612332477020145 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-20 pywws contributors # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """Low level USB interface to weather station, using python-libusb1. Introduction ============ This module handles low level communication with the weather station via the `python-libusb1 `_ library. It is one of several USB device modules, each of which uses a different USB library interface. See :ref:`Installation - USB library` for details. Testing ======= Run :py:mod:`pywws-testweatherstation ` with increased verbosity so it reports which USB device access module is being used:: pywws-testweatherstation -vv 11:30:35:pywws.logger:pywws version 15.01.0 11:30:35:pywws.logger:Python version 3.3.5 (default, Mar 27 2014, 17:16:46) [GCC] 11:30:35:pywws.weatherstation.CUSBDrive:using pywws.device_libusb1 0000 55 aa ff ff ff ff ff ff ff ff ff ff ff ff ff ff 05 20 01 41 11 00 00 00 81 7f 00 f0 0f 00 50 04 0020 f9 25 74 26 00 00 00 00 00 00 00 15 01 15 11 31 41 23 c8 00 00 00 46 2d 2c 01 64 80 c8 00 00 00 0040 64 00 64 80 a0 28 80 25 a0 28 80 25 03 36 00 05 6b 00 00 0a 00 f4 01 12 00 00 00 00 00 00 00 00 0060 00 00 5a 0a 63 0a 41 01 70 00 dc 01 08 81 dc 01 c5 81 68 01 75 81 95 28 e0 25 24 29 d9 25 fd 02 0080 b9 02 f4 ff fd ff 85 ff 91 ff 6c 09 00 14 10 19 06 29 12 02 01 19 32 11 09 09 05 18 12 03 28 13 00a0 00 13 07 19 18 28 13 01 18 23 21 13 09 24 13 02 13 09 24 13 33 13 09 24 13 02 12 07 28 12 50 13 00c0 09 24 13 02 13 10 14 16 18 12 02 07 19 00 14 02 14 22 39 13 01 04 10 28 15 01 15 03 48 12 03 10 00e0 22 02 13 01 30 21 24 12 07 28 11 59 13 03 06 06 43 12 04 13 00 04 12 04 13 00 04 12 07 31 03 34 API === """ __docformat__ = "restructuredtext en" import libusb1 import sys import usb1 class USBDevice(object): """Low level USB device access via python-libusb1 library. :param idVendor: the USB "vendor ID" number, for example 0x1941. :type idVendor: int :param idProduct: the USB "product ID" number, for example 0x8021. :type idProduct: int """ def __init__(self, idVendor, idProduct): self.context = usb1.USBContext() self.dev = self.context.openByVendorIDAndProductID(idVendor, idProduct) if not self.dev: raise IOError("Weather station device not found") if sys.platform.startswith('linux'): if self.dev.kernelDriverActive(0): self.dev.detachKernelDriver(0) self.dev.resetDevice() self.dev.claimInterface(0) def read_data(self, size): """Receive data from the device. If the read fails for any reason, an :obj:`IOError` exception is raised. :param size: the number of bytes to read. :type size: int :return: the data received. :rtype: list(int) """ result = self.dev.bulkRead(0x81, size, timeout=1200) if not result or len(result) < size: raise IOError('pywws.device_libusb1.USBDevice.read_data failed') # Python2 libusb1 version 1.5 and earlier returns a string if not isinstance(result[0], int): result = map(ord, result) return list(result) def write_data(self, buf): """Send data to the device. If the write fails for any reason, an :obj:`IOError` exception is raised. :param buf: the data to send. :type buf: list(int) :return: success status. :rtype: bool """ if sys.version_info[0] < 3: str_buf = ''.join(map(chr, buf)) else: str_buf = bytes(buf) result = self.dev.controlWrite( libusb1.LIBUSB_ENDPOINT_OUT | libusb1.LIBUSB_TYPE_CLASS | libusb1.LIBUSB_RECIPIENT_INTERFACE, libusb1.LIBUSB_REQUEST_SET_CONFIGURATION, 0x200, 0, str_buf, timeout=50) if result != len(buf): raise IOError('pywws.device_libusb1.USBDevice.write_data failed') return True pywws-24.2.0/src/pywws/device_pyusb.py0000644000200200001440000001264113612332477017744 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-20 pywws contributors # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """Low level USB interface to weather station, using PyUSB v0.4. Introduction ============ This module handles low level communication with the weather station via the `PyUSB `_ library. It is one of several USB device modules, each of which uses a different USB library interface. See :ref:`Installation - USB library` for details. Testing ======= Run :py:mod:`pywws.testweatherstation` with increased verbosity so it reports which USB device access module is being used:: python -m pywws.testweatherstation -vv 18:28:09:pywws.weatherstation.CUSBDrive:using pywws.device_pyusb 0000 55 aa ff ff ff ff ff ff ff ff ff ff ff ff ff ff 05 20 01 41 11 00 00 00 81 00 00 0f 05 00 e0 51 0020 03 27 ce 27 00 00 00 00 00 00 00 12 02 14 18 27 41 23 c8 00 00 00 46 2d 2c 01 64 80 c8 00 00 00 0040 64 00 64 80 a0 28 80 25 a0 28 80 25 03 36 00 05 6b 00 00 0a 00 f4 01 12 00 00 00 00 00 00 00 00 0060 00 00 49 0a 63 12 05 01 7f 00 36 01 60 80 36 01 60 80 bc 00 7b 80 95 28 12 26 6c 28 25 26 c8 01 0080 1d 02 d8 00 de 00 ff 00 ff 00 ff 00 00 11 10 06 01 29 12 02 01 19 32 11 09 09 05 18 12 01 22 13 00a0 14 11 11 04 15 04 11 12 17 05 12 11 09 02 15 26 12 02 11 07 05 11 09 02 15 26 12 02 11 07 05 11 00c0 09 10 09 12 12 02 02 12 38 12 02 07 19 00 11 12 16 03 27 12 02 03 11 00 11 12 16 03 27 11 12 26 00e0 21 32 11 12 26 21 32 12 02 06 19 57 12 02 06 19 57 12 02 06 19 57 12 02 06 19 57 12 02 06 19 57 API === """ __docformat__ = "restructuredtext en" import platform import usb class USBDevice(object): """Low level USB device access via PyUSB library. :param idVendor: the USB "vendor ID" number, for example 0x1941. :type idVendor: int :param idProduct: the USB "product ID" number, for example 0x8021. :type idProduct: int """ def __init__(self, idVendor, idProduct): dev = self._find_device(idVendor, idProduct) if not dev: raise IOError("Weather station device not found") self.devh = dev.open() if not self.devh: raise IOError("Open device failed") self.devh.reset() ## if platform.system() is 'Windows': ## self.devh.setConfiguration(1) try: self.devh.claimInterface(0) except usb.USBError: # claim interface failed, try detaching kernel driver first if not hasattr(self.devh, 'detachKernelDriver'): raise RuntimeError( "Please upgrade pyusb (or python-usb) to 0.4 or higher") try: self.devh.detachKernelDriver(0) self.devh.claimInterface(0) except usb.USBError: raise IOError("Claim interface failed") # device may have data left over from an incomplete read for i in range(4): try: self.devh.interruptRead(0x81, 8, 1200) except usb.USBError: break def __del__(self): if self.devh: try: self.devh.releaseInterface() except usb.USBError: # interface was not claimed. No problem pass def _find_device(self, idVendor, idProduct): """Find a USB device by product and vendor id.""" for bus in usb.busses(): for device in bus.devices: if (device.idVendor == idVendor and device.idProduct == idProduct): return device return None def read_data(self, size): """Receive data from the device. If the read fails for any reason, an :obj:`IOError` exception is raised. :param size: the number of bytes to read. :type size: int :return: the data received. :rtype: list(int) """ result = self.devh.interruptRead(0x81, size, 1200) if result is None or len(result) < size: raise IOError('pywws.device_libusb.USBDevice.read_data failed') return list(result) def write_data(self, buf): """Send data to the device. If the write fails for any reason, an :obj:`IOError` exception is raised. :param buf: the data to send. :type buf: list(int) :return: success status. :rtype: bool """ result = self.devh.controlMsg( usb.ENDPOINT_OUT + usb.TYPE_CLASS + usb.RECIP_INTERFACE, usb.REQ_SET_CONFIGURATION, buf, value=0x200, timeout=50) if result != len(buf): raise IOError('pywws.device_libusb.USBDevice.write_data failed') return True pywws-24.2.0/src/pywws/device_pyusb1.py0000644000200200001440000001122513612332477020022 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-20 pywws contributors # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """Low level USB interface to weather station, using PyUSB v1.0. Introduction ============ This module handles low level communication with the weather station via the `PyUSB `_ library (version 1.0). It is one of several USB device modules, each of which uses a different USB library interface. See :ref:`Installation - USB library` for details. Testing ======= Run :py:mod:`pywws.testweatherstation` with increased verbosity so it reports which USB device access module is being used:: python -m pywws.testweatherstation -vv 18:28:09:pywws.weatherstation.CUSBDrive:using pywws.device_pyusb1 0000 55 aa ff ff ff ff ff ff ff ff ff ff ff ff ff ff 05 20 01 41 11 00 00 00 81 00 00 0f 05 00 e0 51 0020 03 27 ce 27 00 00 00 00 00 00 00 12 02 14 18 27 41 23 c8 00 00 00 46 2d 2c 01 64 80 c8 00 00 00 0040 64 00 64 80 a0 28 80 25 a0 28 80 25 03 36 00 05 6b 00 00 0a 00 f4 01 12 00 00 00 00 00 00 00 00 0060 00 00 49 0a 63 12 05 01 7f 00 36 01 60 80 36 01 60 80 bc 00 7b 80 95 28 12 26 6c 28 25 26 c8 01 0080 1d 02 d8 00 de 00 ff 00 ff 00 ff 00 00 11 10 06 01 29 12 02 01 19 32 11 09 09 05 18 12 01 22 13 00a0 14 11 11 04 15 04 11 12 17 05 12 11 09 02 15 26 12 02 11 07 05 11 09 02 15 26 12 02 11 07 05 11 00c0 09 10 09 12 12 02 02 12 38 12 02 07 19 00 11 12 16 03 27 12 02 03 11 00 11 12 16 03 27 11 12 26 00e0 21 32 11 12 26 21 32 12 02 06 19 57 12 02 06 19 57 12 02 06 19 57 12 02 06 19 57 12 02 06 19 57 API === """ __docformat__ = "restructuredtext en" import sys import usb.core import usb.util class USBDevice(object): """Low level USB device access via PyUSB 1.0 library. :param idVendor: the USB "vendor ID" number, for example 0x1941. :type idVendor: int :param idProduct: the USB "product ID" number, for example 0x8021. :type idProduct: int """ def __init__(self, idVendor, idProduct): self.dev = usb.core.find(idVendor=idVendor, idProduct=idProduct) if not self.dev: raise IOError("Weather station device not found") if sys.platform.startswith('linux'): try: detach = self.dev.is_kernel_driver_active(0) except NotImplementedError: detach = True if detach: try: self.dev.detach_kernel_driver(0) except usb.core.USBError: pass self.dev.reset() self.dev.set_configuration() usb.util.claim_interface(self.dev, 0) def read_data(self, size): """Receive data from the device. If the read fails for any reason, an :obj:`IOError` exception is raised. :param size: the number of bytes to read. :type size: int :return: the data received. :rtype: list(int) """ result = self.dev.read(0x81, size, timeout=1200) if not result or len(result) < size: raise IOError('pywws.device_pyusb1.USBDevice.read_data failed') return list(result) def write_data(self, buf): """Send data to the device. If the write fails for any reason, an :obj:`IOError` exception is raised. :param buf: the data to send. :type buf: list(int) :return: success status. :rtype: bool """ bmRequestType = usb.util.build_request_type( usb.util.ENDPOINT_OUT, usb.util.CTRL_TYPE_CLASS, usb.util.CTRL_RECIPIENT_INTERFACE ) result = self.dev.ctrl_transfer( bmRequestType=bmRequestType, bRequest=usb.REQ_SET_CONFIGURATION, data_or_wLength=buf, wValue=0x200, timeout=50) if result != len(buf): raise IOError('pywws.device_pyusb1.USBDevice.write_data failed') return True pywws-24.2.0/src/pywws/examples/0000755000200200001440000000000014556655656016542 5ustar jimusers00000000000000pywws-24.2.0/src/pywws/examples/graph_templates/0000755000200200001440000000000014556655656021721 5ustar jimusers00000000000000pywws-24.2.0/src/pywws/examples/graph_templates/2008.png.xml0000644000200200001440000000461113305436026023574 0ustar jimusers00000000000000 600, 400 year=2008, month=1, day=1, hour=0 year=2008, month=12, day=31, hour=0 %b %Y Temperature (C) -10, 55 monthly boxwidth / 2 1 Mean daytime max data['idx'] - timedelta(days=9) data['temp_out_max_ave'] 6 Highest daytime max data['temp_out_max_hi_t'] data['temp_out_max_hi'] 3 Mean nighttime min data['idx'] - timedelta(days=22) data['temp_out_min_ave'] 5 Lowest nighttime min data['temp_out_min_lo_t'] data['temp_out_min_lo'] 0, 70 monthly 5 data['idx'] - timedelta(days=16) data['rain'] Monthly rainfall (mm) pywws-24.2.0/src/pywws/examples/graph_templates/2009.png.xml0000644000200200001440000000461713305436026023603 0ustar jimusers00000000000000 600, 400 year=2009, month=1, day=1, hour=0 year=2009, month=12, day=31, hour=0 %b %Y Temperature (C) -10, 55 monthly boxwidth / 2 1 Mean daytime max data['start'] + timedelta(days=20) data['temp_out_max_ave'] 6 Highest daytime max data['temp_out_max_hi_t'] data['temp_out_max_hi'] 3 Mean nighttime min data['start'] + timedelta(days=7) data['temp_out_min_ave'] 5 Lowest nighttime min data['temp_out_min_lo_t'] data['temp_out_min_lo'] 0, 70 monthly 5 data['start'] + timedelta(days=14) data['rain'] Monthly rainfall (mm) pywws-24.2.0/src/pywws/examples/graph_templates/2016candle.png.xml0000644000200200001440000000424113305436026024741 0ustar jimusers00000000000000 600, 600 pngcairo font "arial,11" year=2016, month=1, day=1, hour=0 year=2016, month=12, day=31, hour=23 %b %Y Temperatur (℃) -20, 50 ytics monthly rgb "#f44336" data['start'] + timedelta(days=15) (data['temp_out_min_ave'], data['temp_out_min_lo'], data['temp_out_max_hi'], data['temp_out_max_ave']) rgb "#607d8b" data['start'] + timedelta(days=15) (data['temp_out_ave'], data['temp_out_ave'], data['temp_out_ave'], data['temp_out_ave']) pywws-24.2.0/src/pywws/examples/graph_templates/24hrs.png.xml0000644000200200001440000000440013305436026024141 0ustar jimusers00000000000000 600, 800 hours=24 2 %H%M -10, 35 raw 1 Temperature (C) data['temp_out'] 3 dew_point(data['temp_out'], data['hum_out']) Dew point (C) Wind speed (mph) 0, 30 raw 4 wind_mph(data['wind_gust']) gust 3 wind_mph(data['wind_ave']) average 0, 5 hourly 5 data['idx'].replace(minute=30, second=0) data['rain'] Hourly rainfall (mm) hourly 2 data['rel_pressure'] Pressure (hPa) 960, 1050 pywws-24.2.0/src/pywws/examples/graph_templates/24hrs_average_winddir.png.xml0000644000200200001440000000430113305436026027353 0ustar jimusers00000000000000 600, 400 7 7 hours=24 2 %H%M 1 Wind speed (mph) 0, 35 raw 3 wind_mph(data['wind_ave']) average 4 (None,wind_mph(data['wind_gust']))[data['wind_gust']-data['wind_ave']>1.0] gust Wind direction () 0, 360 45 ('N' 0, 'E' 90, 'S' 180, 'W' 270, 'N' 360) raw 2 winddir_average(source[data['idx']-timedelta(minutes=24): data['idx']+timedelta(minutes=24)],0.5,9) pywws-24.2.0/src/pywws/examples/graph_templates/24hrs_full_features.png.xml0000644000200200001440000000622013305436026027063 0ustar jimusers00000000000000 600, 1000 4 4 hours=24 2 %H%M -10, 35 0, 100 C % raw 1 Temperature (C) data['temp_out'] 3 dew_point(data['temp_out'], data['hum_out']) Dew point (C) 2 data['hum_out'] Humidity (%) x1y2 Wind speed (mph) 0, 30 raw 4 wind_mph(data['wind_gust']) gust 3 wind_mph(data['wind_ave']) average Wind direction () 0, 360 45 ('N' 0, 'E' 90, 'S' 180, 'W' 270, 'N' 360) raw 2 (None, data['wind_dir'] * 22.5)[data['wind_ave'] > 0.5] Rainfall (mm) 0, 5 0, 15 hourly total hourly 5 data['idx'].replace(minute=30, second=0) data['rain'] Hourly 3 x1y2 data['rain'] + last_ycalc Total hourly 2 data['rel_pressure'] Pressure (hPa) 960, 1050 pywws-24.2.0/src/pywws/examples/graph_templates/28days.png.xml0000644000200200001440000000470213305436026024316 0ustar jimusers00000000000000 600, 800 weeks=4 %Y/%m/%d Temperature (C) -10, 45 daily boxwidth / 2 1 Daytime max data['start'] + timedelta(hours=18) data['temp_out_max'] 3 Nighttime min data['start'] + timedelta(hours=6) data['temp_out_min'] Wind speed (mph) 0, 30 hourly 4 wind_mph(data['wind_gust']) gust 3 wind_mph(data['wind_ave']) average 0, 30 daily 5 data['start'] + timedelta(hours=12) data['rain'] Daily rainfall (mm) hourly 2 data['rel_pressure'] Pressure (hPa) 960, 1050 pywws-24.2.0/src/pywws/examples/graph_templates/7days.png.xml0000644000200200001440000000436313305436026024236 0ustar jimusers00000000000000 600, 800 weeks=1 %a %d -10, 35 hourly 1 Temperature (C) data['temp_out'] 3 dew_point(data['temp_out'], data['hum_out']) Dew point (C) Wind speed (mph) 0, 30 hourly 4 wind_mph(data['wind_gust']) gust 3 wind_mph(data['wind_ave']) average 0, 5 hourly 5 data['idx'].replace(minute=30, second=0) data['rain'] Hourly rainfall (mm) hourly 2 data['rel_pressure'] Pressure (hPa) 960, 1050 pywws-24.2.0/src/pywws/examples/graph_templates/Oct_08.png.xml0000644000200200001440000000476013305436026024244 0ustar jimusers00000000000000 600, 800 year=2008, month=10, day=1 year=2008, month=11, day=1 %B %Y %d -10, 30 daily boxwidth / 2 1 Daytime max temp (C) data['start'] + timedelta(hours=18) data['temp_out_max'] 3 Nighttime min temp (C) data['start'] + timedelta(hours=6) data['temp_out_min'] 0, 30 hourly 4 wind_mph(data['wind_gust']) Wind speed: gust (mph) 3 wind_mph(data['wind_ave']) average (mph) 0, 32 daily 5 data['start'] + timedelta(hours=12) data['rain'] Daily rainfall (mm) hourly 2 data['rel_pressure'] Pressure (hPa) 960, 1050 pywws-24.2.0/src/pywws/examples/graph_templates/humidex.png.xml0000644000200200001440000000440013305436026024642 0ustar jimusers00000000000000 Humidity Index, Bands indicate apparent discomfort in standard on-site working conditions 1820, 1024 hours=48 2 %H%M 29, 55 29, 55 Humidex raw Humidex cadhumidex(data['temp_out'],data['hum_out']) 4 x1y2 HI > 54, Heat Stroke Probable 54 x1y2 1 HI > 45, Dangerous 45 x1y2 8 HI > 40, Intense 40 x1y2 6 HI > 35, Evident 35 x1y2 2 HI > 30, Noticeable 30 x1y2 3 pywws-24.2.0/src/pywws/examples/graph_templates/pngcairo/0000755000200200001440000000000014556655656023523 5ustar jimusers00000000000000pywws-24.2.0/src/pywws/examples/graph_templates/pngcairo/2014.png.xml0000644000200200001440000000335213305436026025374 0ustar jimusers00000000000000 pngcairo enhanced font "arial,10" rounded 600, 600 5 year=2014, month=1, day=1, hour=0 year=2014, month=12, day=31, hour=0 %b %Y 1 Temperature (°C) -10, 55 -10, 55 monthly boxwidth / 2 1 Mean daytime max data['start'] + timedelta(days=20) data['temp_out_max_ave'] 8 Highest daytime max data['temp_out_max_hi_t'] data['temp_out_max_hi'] 3 Mean nighttime min data['start'] + timedelta(days=7) data['temp_out_min_ave'] 5 Lowest nighttime min data['temp_out_min_lo_t'] data['temp_out_min_lo'] 0, 180 0, 180 monthly 5 data['start'] + timedelta(days=14) data['rain'] Monthly rainfall (mm) pywws-24.2.0/src/pywws/examples/graph_templates/pngcairo/2015.png.xml0000644000200200001440000000335213305436026025375 0ustar jimusers00000000000000 pngcairo enhanced font "arial,10" rounded 600, 600 5 year=2015, month=1, day=1, hour=0 year=2015, month=12, day=31, hour=0 %b %Y 1 Temperature (°C) -10, 55 -10, 55 monthly boxwidth / 2 1 Mean daytime max data['start'] + timedelta(days=20) data['temp_out_max_ave'] 8 Highest daytime max data['temp_out_max_hi_t'] data['temp_out_max_hi'] 3 Mean nighttime min data['start'] + timedelta(days=7) data['temp_out_min_ave'] 5 Lowest nighttime min data['temp_out_min_lo_t'] data['temp_out_min_lo'] 0, 180 0, 180 monthly 5 data['start'] + timedelta(days=14) data['rain'] Monthly rainfall (mm) pywws-24.2.0/src/pywws/examples/graph_templates/pngcairo/24hrs.png.xml0000644000200200001440000000510413305436026025745 0ustar jimusers00000000000000 pngcairo enhanced font "arial,10" rounded 600, 1000 7 7 hours=24 2 %H%M set style circle radius 150 1 -10, 35 -10, 35 raw rgb "red" Temperature (°C) data['temp_out'] rgb "green" dew_point(data['temp_out'], data['hum_out']) Dew point (°C) 1 Wind speed (mph) 0, 35 0, 35 raw rgb "blue" wind_mph(data['wind_ave']) average (None,wind_mph(data['wind_gust']))[data['wind_gust']-data['wind_ave']>1.0] gust 1 0, 360 45 ('N' 0, 'E' 90, 'S' 180, 'W' 270, 'N' 360) raw 2 (None,winddir_degrees(data['wind_dir']))[data['wind_ave']>0.5] Wind direction Rainfall (mm) 1 0, 10 0, 50 hourly total hourly rgb "cyan" data['idx'].replace(minute=30, second=0) data['rain'] hourly rgb "blue" x1y2 data['rain'] + last_ycalc total hourly rgb "black" data['rel_pressure'] Pressure (hPa) 960, 1060 960, 1060 pywws-24.2.0/src/pywws/examples/graph_templates/pngcairo/28days.png.xml0000644000200200001440000000502313305436026026115 0ustar jimusers00000000000000 pngcairo enhanced font "arial,10" rounded 600, 800 weeks=4 %Y/%m/%d 7 8 set style circle radius 150 Temperature (°C) 2 -10, 45 -10, 45 daily boxwidth / 2 rgb "red" day max data['start'] + timedelta(hours=18) data['temp_out_max'] rgb "blue" night min data['start'] + timedelta(hours=6) data['temp_out_min'] rgb "green" average data['start'] + timedelta(hours=12) data['temp_out_ave'] Wind speed (mph) 1 0, 35 0, 35 hourly rgb "blue" wind_mph(data['wind_ave']) average (None,wind_mph(data['wind_gust']))[data['wind_gust']-data['wind_ave']>1.0] gust Rainfall (mm) 1 0, 40 daily 0, 200 total daily rgb "cyan" data['start'] + timedelta(hours=14) data['rain'] daily rgb "blue" x1y2 data['rain'] + last_ycalc total hourly rgb "black" data['rel_pressure'] Pressure (hPa) 960, 1060 960, 1060 pywws-24.2.0/src/pywws/examples/graph_templates/pngcairo/7days.png.xml0000644000200200001440000000421713305436026026036 0ustar jimusers00000000000000 pngcairo enhanced font "arial,10" rounded 600, 800 7 7 weeks=1 %a %d set style circle radius 150 2 -10, 35 -10, 35 hourly rgb "red" Temperature (°C) data['temp_out'] rgb "green" dew_point(data['temp_out'], data['hum_out']) Dew point (°C) 1 Wind speed (mph) 0, 35 0, 35 hourly rgb "blue" wind_mph(data['wind_ave']) average (None,wind_mph(data['wind_gust']))[data['wind_gust']-data['wind_ave']>1.0] gust Rainfall (mm) 1 0, 10 0, 80 hourly total hourly rgb "cyan" data['idx'].replace(minute=30, second=0) data['rain'] hourly rgb "blue" x1y2 data['rain'] + last_ycalc total hourly rgb "black" data['rel_pressure'] Pressure (hPa) 960, 1060 960, 1060 pywws-24.2.0/src/pywws/examples/graph_templates/pngcairo/README.txt0000644000200200001440000000055213305436026025176 0ustar jimusers00000000000000If your installation of gnuplot has the pngcairo terminal available you can improve the appearance of your plots by using it instead of the normal png terminal. This directory includes a set of graph templates using the pngcairo terminal. They also specify colours by name rather than numerical index, and use small circles for wind direction instead of crosses.pywws-24.2.0/src/pywws/examples/graph_templates/pngcairo/rose_24hrs.png.xml0000644000200200001440000000077413305436026027005 0ustar jimusers00000000000000 pngcairo enhanced font "arial,10" rounded Wind speed (Beaufort) distribution over 24 hours ending %H:%M hours=24 raw wind_bft(data['wind_ave']) 36 1, 2, 3, 4, 5 'rgb "yellow"', 'rgb "blue"', 'rgb "cyan"', 'rgb "magenta"', 'rgb "green"', 'rgb "red"' pywws-24.2.0/src/pywws/examples/graph_templates/pngcairo/tweet.png.xml0000644000200200001440000000256113305436026026137 0ustar jimusers00000000000000 pngcairo enhanced font "arial,8" rounded 506, 253 7 7 hours=24 2 %H%M 1 -10, 35 -10, 35 10 10 raw 1 Temperature (°C) data['temp_out'] 3 dew_point(data['temp_out'], data['hum_out']) Dew point (°C) 1.6 Rainfall (mm) 0, 10 0, 50 hourly total hourly 5 data['idx'].replace(minute=30, second=0) data['rain'] hourly 3 x1y2 data['rain'] + last_ycalc total pywws-24.2.0/src/pywws/examples/graph_templates/rose_24hrs.png.xml0000644000200200001440000000235213305436026025175 0ustar jimusers00000000000000 Wind over the last day (mph) hours=24 raw wind_mph(data['wind_ave']) 31 0.5, 3.5, 7.5, 12.5, 18.5, 24.5, 31.5 0, 6, 7, 2, 5, 3, 4, 1 pywws-24.2.0/src/pywws/examples/graph_templates/rose_7days_nights.png.xml0000644000200200001440000000322713305436026026640 0ustar jimusers00000000000000 Wind over the last week (mph) hours=24 * 7 Day raw data['idx'].hour >= 9 and data['idx'].hour < 21 wind_mph(data['wind_ave']) 21 0.5, 3.5, 7.5, 12.5, 18.5, 24.5, 31.5 0, 6, 7, 2, 5, 3, 4, 1 Night raw data['idx'].hour < 9 or data['idx'].hour >= 21 wind_mph(data['wind_ave']) 21 0.5, 3.5, 7.5, 12.5, 18.5, 24.5, 31.5 0, 6, 7, 2, 5, 3, 4, 1 pywws-24.2.0/src/pywws/examples/graph_templates/tweet.png.xml0000755000200200001440000000232413305436026024335 0ustar jimusers00000000000000 png small size 440,220 6 7 hours=24 2 %H%M 1 -10, 35 raw 1 Temperature (C) data['temp_out'] 3 dew_point(data['temp_out'], data['hum_out']) Dew point (C) 1.6 Rainfall (mm) 0, 6 0, 30 hourly total hourly 5 data['idx'].replace(minute=30, second=0) data['rain'] hourly 3 x1y2 data['rain'] + last_ycalc total pywws-24.2.0/src/pywws/examples/modules/0000755000200200001440000000000014556655656020212 5ustar jimusers00000000000000pywws-24.2.0/src/pywws/examples/modules/aws_api_gw_service.py0000644000200200001440000001040613357605510024403 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2018 pywws contributors # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. """Upload weather data to an AWS Gateway API (or other) service. This is for any service that accepts key value data via a GET method. This supports optional extra headers. * Additional dependency: http://docs.python-requests.org/ * Example ``weather.ini`` configuration:: [aws_api_gw_service] api url = https://my-aws-api-gw.execute-api.eu-west-1.amazonaws.com/weather http headers = [('x-api-key', 'my-api-key'), ('another-one', 'spam-val')] [logged] services = ['aws_api_gw_service', 'metoffice'] [live] services = ['aws_api_gw_service', 'metoffice'] """ from __future__ import absolute_import, unicode_literals from ast import literal_eval from contextlib import contextmanager from datetime import timedelta import logging import os import sys import requests import pywws from pywws.conversions import rain_inch import pywws.service __docformat__ = "restructuredtext en" service_name = os.path.splitext(os.path.basename(__file__))[0] logger = logging.getLogger(__name__) class ToService(pywws.service.CatchupDataService): catchup = 100 config = { 'http headers': (None, False, None), 'api url' : ('', True, None), } interval = timedelta(seconds=300) logger = logger service_name = service_name template = """ #live# #hum_in "'hum_in' : '%.d',"# #temp_in "'temp_in' : '%.1f',"# #hum_out "'hum_out' : '%.d',"# #temp_out "'temp_out' : '%.1f',"# #calc "dew_point(data['temp_out'], data['hum_out'])" "'temp_dewpt' : '%.1f',"# #rel_pressure "'abs_pressure' : '%.4f',"# #wind_ave "'wind_ave' : '%.2f'," "" "wind_mph(x)"# #wind_gust "'wind_gust' : '%.2f'," "" "wind_mph(x)"# #wind_dir "'wind_dir' : '%.0f'," "" "winddir_degrees(x)"# #calc "rain_hour(data)" "'rain' : '%g',"# #calc "rain_day(data)" "'rain_day' : '%g',"# #calc "wind_chill(data['temp_out'], data['wind_ave'])" "'wind_chill' : '%.1f',"# #calc "apparent_temp(data['temp_out'], data['hum_out'], data['wind_ave'])" "'temp_apprt' : '%.1f',"# #calc "cloud_base(data['temp_out'], data['hum_out'])" "'cloud_base' : '%.1f',"# #idx "'tdate' : '%Y-%m-%d',"# #idx "'ttime' : '%H:%M:%S',"# """ def __init__(self, context, check_params=True): super(ToService, self).__init__(context, check_params) # initialise rain history last_update = context.status.get_datetime('last update', service_name) if last_update: last_update = context.calib_data.nearest(last_update) self.last_rain = context.calib_data[last_update]['rain'] else: self.last_rain = None @contextmanager def session(self): with requests.Session() as session: yield session def upload_data(self, session, prepared_data={}): try: if self.params['http headers']: for header in literal_eval(self.params['http headers']): session.headers.update({header[0]: header[1]}) rsp = session.get(self.params['api url'], params=prepared_data, timeout=60) except Exception as ex: return False, repr(ex) if rsp.status_code != 200: return False, 'http status: {:d}'.format(rsp.status_code) rsp = rsp.json() if rsp: return True, 'server response "{!r}"'.format(rsp) return True, 'OK' if __name__ == "__main__": sys.exit(pywws.service.main(ToService)) pywws-24.2.0/src/pywws/examples/modules/calib_jim.py0000755000200200001440000000426413305436026022461 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-14 Jim Easterbrook jim@jim-easterbrook.me.uk # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. from datetime import datetime class Calib(object): """Jim's weather station calibration class.""" def __init__(self, params, raw_data): # pressure sensor went wrong on 19th August 2011 self.pressure_fault = datetime(2011, 8, 19, 11, 0, 0) # finally replaced weather station on 11th November 2011 self.new_station = datetime(2011, 11, 11, 12, 5, 0) def calib(self, raw): result = dict(raw) # set relative pressure and tweak temperature and humidity to make old # and new stations closer if result['idx'] > self.new_station: result['rel_pressure'] = result['abs_pressure'] + 5.2 if result['temp_out'] is not None: result['temp_out'] += 0.6 if result['hum_out'] is not None: result['hum_out'] -= 1 else: if result['idx'] > self.pressure_fault: # pressure readings are nonsense since sensor failed result['abs_pressure'] = None result['rel_pressure'] = None else: result['rel_pressure'] = result['abs_pressure'] + 7.4 if result['temp_out'] is not None: result['temp_out'] -= 0.6 if result['hum_out'] is not None: result['hum_out'] += 2 return result pywws-24.2.0/src/pywws/examples/modules/default.py0000644000200200001440000000235713357605510022175 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-14 Jim Easterbrook jim@jim-easterbrook.me.uk # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class Calib(object): """Minimum weather station calibration class.""" def __init__(self, params, raw_data): self.pressure_offset = float(params.get('config', 'pressure offset')) def calib(self, raw): result = dict(raw) # calculate relative pressure result['rel_pressure'] = result['abs_pressure'] + self.pressure_offset return result pywws-24.2.0/src/pywws/examples/modules/filter_wind_dir.py0000644000200200001440000000333413357605510023711 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-14 Jim Easterbrook jim@jim-easterbrook.me.uk # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. from datetime import timedelta import pywws.process class Calib(object): """Weather station calibration class with wind direction filter.""" def __init__(self, params, raw_data): self.pressure_offset = float(params.get('config', 'pressure offset')) self.raw_data = raw_data self.wind_fil_aperture = timedelta(minutes=29) def calib(self, raw): result = dict(raw) # calculate relative pressure result['rel_pressure'] = result['abs_pressure'] + self.pressure_offset # filter wind direction stop = result['idx'] start = stop - self.wind_fil_aperture wind_filter = pywws.process.WindFilter(decay=0.8) for data in self.raw_data[start:stop]: wind_filter.add(data) wind_filter.add(raw) speed, result['wind_dir'] = wind_filter.result() return result pywws-24.2.0/src/pywws/examples/modules/remove_temperature_spikes.py0000644000200200001440000000434213357605510026035 0ustar jimusers00000000000000# pywws - Python software for USB Wireless Weather Stations # http://github.com/jim-easterbrook/pywws # Copyright (C) 2008-14 Jim Easterbrook jim@jim-easterbrook.me.uk # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. from datetime import timedelta import logging from pywws.constants import SECOND logger = logging.getLogger(__name__) MINUTEx30 = timedelta(minutes=30) class Calib(object): """Weather station calibration class with temperature spike removal.""" def __init__(self, params, raw_data): self.raw_data = raw_data self.pressure_offset = float(params.get('config', 'pressure offset')) def calib(self, raw): result = dict(raw) # try to remove spikes in outside temperature if result['temp_out'] is not None: # get last 30 mins valid temperatures history = [] for data in self.raw_data[result['idx'] - MINUTEx30: result['idx'] + SECOND]: if data['temp_out'] is not None: history.append(data['temp_out']) history.sort() if len(history) >= 4: median = history[(len(history) - 1) / 2] if abs(result['temp_out'] - median) > 1.5: logger.warning( 'spike? %s %s', str(history), str(result['temp_out'])) if abs(result['temp_out'] - median) > 2.0: result['temp_out'] = None # calculate relative pressure result['rel_pressure'] = result['abs_pressure'] + self.pressure_offset return result pywws-24.2.0/src/pywws/examples/scripts/0000755000200200001440000000000014556655656020231 5ustar jimusers00000000000000pywws-24.2.0/src/pywws/examples/scripts/data_mangling/0000755000200200001440000000000014556655656023016 5ustar jimusers00000000000000pywws-24.2.0/src/pywws/examples/scripts/data_mangling/README.txt0000644000200200001440000000236713305436026024477 0ustar jimusers00000000000000Data mangling scripts ===================== These scripts must be used with extremem caution! They are provided as starting points for any data modifications you need to do as a result of some unusual event that has affected your data. In all cases, make sure you do the following: 1/ Copy one of the example scripts and edit it to do what you need. 2/ Stop all pywws software, and any cron job that might restart it. 3/ Backup your weather data. 4/ Check that you really have backed up your data. 5/ Run the script. 6/ Check the results, carefully. 7/ If all is well, restart pywws. rain_offset.py -------------- This script subtracts a fixed value from all the rain data in a given range of time stamps. This could be useful if you had an unusual event such as the wind resonating with the rain gauge and tipping the see-saw multiple times. Removing the batteries from the external sensors will reset the rain count, but your data will still have an unwanted jump which a script like this can remove. temperature_despike.py ---------------------- This uses a median filter to remove spikes in the external temperature data, possibly caused by electrical interference. It substitutes a 'missing data' value, rather than attempt to interpolate from adjacent values.pywws-24.2.0/src/pywws/examples/scripts/data_mangling/rain_offset.py0000755000200200001440000000330313357605510025647 0ustar jimusers00000000000000#!/usr/bin/env python from __future__ import print_function __usage__ = """ Remove rain offset from raw data. usage: %s [options] data_dir options are: -h or --help display this help data_dir is the root directory of the weather data (e.g. $(HOME)/weather/data) """ % __file__ from datetime import datetime import getopt import os import sys sys.path.append(os.path.join(os.path.dirname(__file__), '../../..')) import pywws.storage def main(argv=None): if argv is None: argv = sys.argv try: opts, args = getopt.getopt(argv[1:], "h", ['help']) except getopt.error as msg: print('Error: %s\n' % msg, file=sys.stderr) print(__usage__.strip(), file=sys.stderr) return 1 # process options for o, a in opts: if o == '-h' or o == '--help': print(__usage__.strip()) return 0 # check arguments if len(args) != 1: print('Error: 1 argument required\n', file=sys.stderr) print(__usage__.strip(), file=sys.stderr) return 2 data_dir = args[0] # date & time range of data to be changed, in UTC! start = datetime(2013, 10, 26, 15, 23) stop = datetime(2013, 10, 30, 12, 47) # open data store via PywwsContext context = pywws.storage.PywwsContext(data_dir,False) raw_data = context.raw_data # change the data for data in raw_data[start:stop]: data['rain'] -= 263.1 raw_data[data['idx']] = data # make sure it's saved raw_data.flush() # clear calibrated data that needs to be regenerated calib_data = context.calib_data del calib_data[start:] calib_data.flush() # done return 0 if __name__ == "__main__": sys.exit(main()) pywws-24.2.0/src/pywws/examples/scripts/data_mangling/temperature_despike.py0000755000200200001440000000555713357605510027426 0ustar jimusers00000000000000#!/usr/bin/env python from __future__ import print_function __usage__ = """ Remove temperature spikes from raw data. usage: %s [options] data_dir options are: -h or --help display this help -n or --noaction show what would be done but don't modify data data_dir is the root directory of the weather data (e.g. $(HOME)/weather/data) """ % __file__ from datetime import datetime, timedelta import getopt import os import sys sys.path.append(os.path.join(os.path.dirname(__file__), '../../..')) from pywws.constants import SECOND import pywws.storage def main(argv=None): if argv is None: argv = sys.argv try: opts, args = getopt.getopt(argv[1:], "hn", ['help', 'noaction']) except getopt.error as msg: print('Error: %s\n' % msg, file=sys.stderr) print(__usage__.strip(), file=sys.stderr) return 1 # process options noaction = False for o, a in opts: if o == '-h' or o == '--help': print(__usage__.strip()) return 0 elif o == '-n' or o == '--noaction': noaction = True # check arguments if len(args) != 1: print('Error: 1 argument required\n', file=sys.stderr) print(__usage__.strip(), file=sys.stderr) return 2 data_dir = args[0] # date & time range of data to be changed, in UTC! start = datetime(2013, 10, 27, 11, 21) stop = datetime(2013, 10, 29, 18, 32) # open data store via PywwsContext context = pywws.storage.PywwsContext(data_dir,False) raw_data = context.raw_data # process the data aperture = timedelta(minutes=14, seconds=30) # make list of changes to apply after examining the data changes = [] for data in raw_data[start:stop]: if data['temp_out'] is None: continue # get temperatures at nearby times idx = data['idx'] temp_list = [] for local_data in raw_data[idx-aperture:idx+aperture]: temp = local_data['temp_out'] if temp is not None: temp_list.append(temp) if len(temp_list) < 3: continue # get median temp_list.sort() median = temp_list[len(temp_list) / 2] # remove anything too far from median if abs(data['temp_out'] - median) >= 2.5: print(str(idx), temp_list, data['temp_out']) changed = dict(data) changed['temp_out'] = None changes.append(changed) # store the changed data if changes and not noaction: for changed in changes: raw_data[changed['idx']] = changed # make sure it's saved raw_data.flush() # clear calibrated data that needs to be regenerated calib_data = context.calib_data del calib_data[changes[0]['idx']:] calib_data.flush() # done return 0 if __name__ == "__main__": sys.exit(main()) pywws-24.2.0/src/pywws/examples/templates/0000755000200200001440000000000014556655656020540 5ustar jimusers00000000000000pywws-24.2.0/src/pywws/examples/templates/12months.txt0000644000200200001440000000454013305436026022732 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2008-16 pywws contributors # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #encoding html# #timezone local# #monthly# #jump -11# #loop 12# #jump 1# #endloop#
Month Temperature Rainfall
daytime maximum nighttime minimum total rainy days
highest average lowest highest average lowest
#calc "data['start']+DAY" "%B %Y"# #temp_out_max_hi "%.1f °C"# #temp_out_max_ave "%.1f °C"# #temp_out_max_lo "%.1f °C"# #temp_out_min_hi "%.1f °C"# #temp_out_min_ave "%.1f °C"# #temp_out_min_lo "%.1f °C"# #rain "%0.1f mm"# #rain_days "%d"#
pywws-24.2.0/src/pywws/examples/templates/2010_11.txt0000644000200200001440000000423213305436026022140 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2008-16 pywws contributors # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #encoding html# #timezone local# #roundtime True# #daily# #goto "2010-11-01 00:00:00"# #loop 30# #jump 1# #endloop#
24 hours ending Temperature Wind Rainfall
day max night min dir average max gust
#idx "%Y/%m/%d %H:%M %Z"# #temp_out_max "%.1f °C"# #temp_out_min "%.1f °C"# #wind_dir "%s" "-" "winddir_text(x)"# #wind_ave "%.0f mph" "" "wind_mph(x)"# #wind_gust "%.0f mph" "" "wind_mph(x)"# #rain "%0.1f mm"#
pywws-24.2.0/src/pywws/examples/templates/24hrs.txt0000644000200200001440000000506613305436026022225 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2008-16 pywws contributors # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #encoding html# #daily# #timezone local# #roundtime True# #jump -1# #loop 2# #idx " " "" "[x, None][loop_count==1]"# #jump 1# #endloop#
#start "From %H%M %Z on %d %b to" "24 hours ending" "[x, None][loop_count == 2]"# #idx " %H%M %Z on %d %b %Y"# Date & time
Daytime max temp #temp_out_max "%.1f °C"# #temp_out_max_t "%Y/%m/%d%H%M %Z"#
Night min temp #temp_out_min "%.1f °C"# #temp_out_min_t "%Y/%m/%d%H%M %Z"#
Total rainfall #rain "%.1f mm"#
Average wind speed #wind_ave "%.0f mph" "-" "wind_mph(x)"#
Highest gust speed #wind_gust "%.0f mph" "-" "wind_mph(x)"# #wind_gust_t "%Y/%m/%d%H%M %Z"#
 
pywws-24.2.0/src/pywws/examples/templates/6hrs.txt0000644000200200001440000000545113305436026022143 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2008-16 pywws contributors # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #encoding html# #timezone local# #roundtime True# #hourly# #jump -6# #loop 7# #jump 1# #endloop#
Date & time Temp Feels like Humidity Wind Rain Pressure Cloud base
dir ave gust
#idx "%Y/%m/%d" "" "[None, x][x.hour == 0 or loop_count == 7]"# #idx "%H%M %Z"# #temp_out "%.1f °C"# #calc "apparent_temp(data['temp_out'], data['hum_out'], data['wind_ave'])" "%.1f °C"# #hum_out "%d%%"# #wind_dir "%s" "-" "winddir_text(x)"# #wind_ave "%.0f mph" "" "wind_mph(x)"# #wind_gust "%.0f mph" "" "wind_mph(x)"# #rain "%0.1f mm"# #rel_pressure "%.1f hPa"#, #pressure_trend "%s" "" "pressure_trend_text(x)"# #calc "cloud_base(data['temp_out'], data['hum_out'])" "%.1f m"#
pywws-24.2.0/src/pywws/examples/templates/6hrs_html_cp.txt0000644000200200001440000000364713305436026023656 0ustar jimusers00000000000000

START der Auswertung der letzten | Stunde | 6 Stunden | 24 Stunden | 7 Tage | 28 Tage |

#timezone local# #roundtime True# #hourly# #jump -6# #loop 7# #jump 1# #endloop#
Datum & Zeit Temperatur Luftfeuchte Wind Regenmenge Luftdruck
Richtung Durchschnitt Windboe
#idx "%d/%m/%Y/" "" "[None, x][x.hour == 0 or loop_count == 7]"# #idx "%H:%M %Z"# #temp_out "%.1f °C"# #hum_out "%d%%"# #wind_dir "%s" "-" "winddir_text(x)"# #wind_ave "%.0f km/h" "" "wind_kmph(x)"# #wind_gust "%.0f km/h" "" "wind_kmph(x)"# #rain "%0.1f mm"# #rel_pressure "%.0f hPa"#, #pressure_trend "%s" "" "pressure_trend_text(x)"#

Graphen der letzten 6 Stunden pywws-24.2.0/src/pywws/examples/templates/7days.txt0000644000200200001440000000420613305436026022305 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2008-16 pywws contributors # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #encoding html# #timezone local# #roundtime True# #daily# #jump -7# #loop 7# #jump 1# #endloop#
24 hours ending Temperature Wind Rainfall
day max night min dir average max gust
#idx "%Y/%m/%d %H:%M %Z"# #temp_out_max "%.1f °C"# #temp_out_min "%.1f °C"# #wind_dir "%s" "-" "winddir_text(x)"# #wind_ave "%.0f mph" "" "wind_mph(x)"# #wind_gust "%.0f mph" "" "wind_mph(x)"# #rain "%0.1f mm"#
pywws-24.2.0/src/pywws/examples/templates/allmonths.txt0000644000200200001440000000453113305436026023260 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2008-16 pywws contributors # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #encoding html# #timezone local# #monthly# #loop 10000# #jump -1# #endloop#
Month Temperature Rainfall
daytime maximum nighttime minimum total rainy days
highest average lowest highest average lowest
#calc "data['start']+DAY" "%B %Y"# #temp_out_max_hi "%.1f °C"# #temp_out_max_ave "%.1f °C"# #temp_out_max_lo "%.1f °C"# #temp_out_min_hi "%.1f °C"# #temp_out_min_ave "%.1f °C"# #temp_out_min_lo "%.1f °C"# #rain "%0.1f mm"# #rain_days "%d"#
pywws-24.2.0/src/pywws/examples/templates/dmi_borgervejr.txt0000644000200200001440000000340013305436026024251 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2013 x2q x2q@xq2.net # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #raw# #timezone local# #idx "%d/%m/%Y %H:%M:%S"# Humidity: #hum_out "%d%%"# Temp: #temp_out "%.1fC"# Raw Barom: #rel_pressure "%.2fhPa"# Solar: #illuminance "%.0fW/sqm" "" "illuminance_wm2(x)"# Wind Dir: #wind_dir "%.0f" "" "winddir_degrees(x)"# Wind Spd: #wind_ave "%.0fmps"# Wind Gust: #wind_gust "%.0fmps"# Tot Rain: #rain "%0.0fmm"# pywws-24.2.0/src/pywws/examples/templates/dmi_borgervejr_1080.txt0000644000200200001440000000332413305436026024726 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2014-15 pywws contributors # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #raw# #timezone local# #idx "%d/%m/%Y %H:%M:%S"# Humidity: #hum_out "%d%%"# Temp: #temp_out "%.1fC"# Raw Barom: #rel_pressure "%.2fhPa"# Solar: 0W/sqm Wind Dir: #wind_dir "%.0f" "" "winddir_degrees(x)"# Wind Spd: #wind_ave "%.0fmps"# Wind Gust: #wind_gust "%.0fmps"# Tot Rain: #rain "%0.1fmm"# pywws-24.2.0/src/pywws/examples/templates/feed_daily.xml0000644000200200001440000000507313305436026023327 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2008-13 Jim Easterbrook jim@jim-easterbrook.me.uk # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #timezone local# #daily# #jump -1# Stoneleigh Weather - Daily Reports http://www.jim-easterbrook.me.uk/weather/ Daily reports from an amateur weather station in Stoneleigh, Surrey, UK 360 #idx "%A %d %B"# 51.36 -.25 http://www.jim-easterbrook.me.uk/weather/7days/ Temperature: #temp_out_min "%.1fC (min)"# #temp_out_max ", %.1fC (max)"# , Wind: #wind_dir "%s, " "" "winddir_text(x)"# #wind_ave "%.0f mph (ave), " "" "wind_mph(x)"# #wind_gust "%.0f mph (gust), " "" "wind_mph(x)"# Rainfall #rain "%.1f mm"# #idx "daily_%Y_%m_%d"# #idx "%a, %d %b %Y %H:%M:%S %z"# pywws-24.2.0/src/pywws/examples/templates/feed_hourly.xml0000644000200200001440000000527613305436026023554 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2008-13 Jim Easterbrook jim@jim-easterbrook.me.uk # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #timezone local# #roundtime True# #hourly# Stoneleigh Weather - Hourly Reports http://www.jim-easterbrook.me.uk/weather/ Hourly reports from an amateur weather station in Stoneleigh, Surrey, UK 60 #idx "%A %H:%M %Z"# 51.36 -.25 http://www.jim-easterbrook.me.uk/weather/24hrs/ Temperature: #temp_out "%.1fC" "-"# , Wind: #wind_dir "%s, " "" "winddir_text(x)"# #wind_ave "%.0f mph (ave), " "" "wind_mph(x)"# #wind_gust "%.0f mph (gust)" "" "wind_mph(x)"# , Humidity: #hum_out "%d%%"# , Rainfall (hourly) #rain "%.1f mm"# , Pressure: #rel_pressure "%.0f hPa, "# #pressure_trend "%s" "" "pressure_trend_text(x)"# #idx "hourly_%Y_%m_%d_%H_%M_%Z"# #roundtime False# #idx "%a, %d %b %Y %H:%M:%S %z"# pywws-24.2.0/src/pywws/examples/templates/forecast_9am.txt0000644000200200001440000000330613305436026023632 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2008-16 pywws contributors # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #encoding html# #hourly# #timezone local# #roundtime True# #jump -8# #goto "%Y-%m-%d 08:30:00"# #idx "

12 hour weather forecast, computed on %a, %d %b at %H:%M %Z: "# #calc "Zambretti(params, data)" "%s.
NB: this forecast is highly experimental and should not be relied upon.

"# pywws-24.2.0/src/pywws/examples/templates/forecast_tweet.txt0000644000200200001440000000305113305436026024271 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2008-13 Jim Easterbrook jim@jim-easterbrook.me.uk # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #hourly# #timezone local# #roundtime True# #idx "%H:%M %Z:"# TEST: forecast for the next 12 hours: #calc "Zambretti(params, data)"# pywws-24.2.0/src/pywws/examples/templates/forecast_week.txt0000644000200200001440000000346013305436026024100 0ustar jimusers00000000000000#! pywws - Python software for USB Wireless Weather Stations # #! http://github.com/jim-easterbrook/pywws # #! Copyright (C) 2008-16 pywws contributors # #! # #! This program is free software; you can redistribute it and/or # #! modify it under the terms of the GNU General Public License # #! as published by the Free Software Foundation; either version 2 # #! of the License, or (at your option) any later version. # #! # #! This program is distributed in the hope that it will be useful, # #! but WITHOUT ANY WARRANTY; without even the implied warranty of # #! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # #! GNU General Public License for more details. # #! # #! You should have received a copy of the GNU General Public License # #! along with this program; if not, write to the Free Software # #! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # #encoding html# #timezone local# #roundtime True# #hourly# #goto "%Y-%m-%d 00:00:00"# #jump -144# #loop 8# #goto "%Y-%m-%d 08:30:00"# #calc "data['idx']" ""# #calc "Zambretti(params, data)" ""# #jump 16# #endloop#
date & time Forecast for the following 12 hours
%A %d %B, %H:%M %Z%s
pywws-24.2.0/src/pywws/examples/templates/google_charts/0000755000200200001440000000000014556655656023360 5ustar jimusers00000000000000pywws-24.2.0/src/pywws/examples/templates/google_charts/README.txt0000644000200200001440000001413413305436026025034 0ustar jimusers00000000000000How to get google visualisation charts working with pywws 1) Set up a template in pywws to generate JSON data 2) Extract the JSON data using jquery and generate the google charts using javascript 1) Setting up a template in pywws: JSON format is a similar concept to XML in that key identifiers are used to separate data elements. Reference site is: http://www.json.org/ The "[" bracket is used to contain an array, whilst objects are contained within the "{" bracket. WARNING: The jquery function for extracting JSON data is very very sensitive so make sure you have brackets and commas in the correct place. Below is an example template that generates the last 6 x 10 minute intervals of data. live_json.txt ------------------------- (don't include this line in the template) [ #timezone local# #raw# #jump -7# #jump 1# #loop 6# { "Date": "#idx "%m/%d/%Y %H:%M"#", "Time": " #idx "%H:%M %Z"# ", "TempOut": #temp_out "%.1f"#, "FeelsLike": #calc "apparent_temp(data['temp_out'], data['hum_out'], data['wind_ave'])" "%.1f"#, "HumidityOut": #hum_out "%d"#, "WindDirection": " #wind_dir "%s" "-" "winddir_text(x)"# ", "WindAvg": #wind_ave "%.0f" "" "x"#, "WindGust": #wind_gust "%.0f" "" "x"#, "Rain": #calc "data['rain']-prevdata['rain']" "%0.1f"#, "AbsPressure": #abs_pressure "%.1f"# }, #jump 1# #endloop# #jump 1# { "Date": "#idx "%m/%d/%Y %H:%M"#", "Time": " #idx "%H:%M %Z"# ", "TempOut": #temp_out "%.1f"#, "FeelsLike": #calc "apparent_temp(data['temp_out'], data['hum_out'], data['wind_ave'])" "%.1f"#, "HumidityOut": #hum_out "%d"#, "WindDirection": " #wind_dir "%s" "-" "winddir_text(x)"# ", "WindAvg": #wind_ave "%.0f" "" "x"#, "WindGust": #wind_gust "%.0f" "" "x"#, "Rain": #calc "data['rain']-prevdata['rain']" "%0.1f"#, "AbsPressure": #abs_pressure "%.1f"# } ] -----------end of file-------- (don't include this line in the template) Note that the data is each section is identical, however the last "object" contained in the curly brackets"{}" lacks a trailing comma. Also the last element (AbsPressure) lacks a trailing comma. Don't forget the "[]" at the start and end of the template. Finally to keep things simple I removed spaces from the data names. Set this up to run at whatever interval you wish and then upload the resultant data to your website (I use the built in ftp settings in pywws). 2) Extracting the data and generating the google charts: This example will work through a table chart (http://code.google.com/apis/chart/interactive/docs/gallery/table.html) This documentation is based on using the google visualization API. The homepage for this library is http://code.google.com/apis/chart/ In the head section of your html page, you need to setup the jquery reference and the google api reference (lines 1 and 2 of extract below). Then you need to load the "table" package for our example - there are other packages you will need if you are making other charts. ----------extract of HTML HEAD STUFF -------------------