Codebase list pywws / fca84c2
New upstream version 22.9.0 Thorsten Alteholz 1 year, 6 months ago
16 changed file(s) with 91 addition(s) and 89 deletion(s). Raw diff Collapse all Expand all
00 pywws - Python software for USB Wireless Weather Stations
11 http://github.com/jim-easterbrook/pywws
2 Copyright (C) 2008-21 pywws contributors
2 Copyright (C) 2008-22 pywws contributors
33
44 This program is free software; you can redistribute it and/or
55 modify it under the terms of the GNU General Public License
1414 You should have received a copy of the GNU General Public License
1515 along with this program; if not, write to the Free Software
1616 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 Changes in v22.9.0:
19 1/ Reject data if 'pointer' value is invalid due to failing hardware.
20 2/ Updated Weather Underground uploader documentation.
21
22 Changes in v22.3.0:
23 1/ Replace pytz with dateutil.tz.
24 2/ Fix some hidapi USB problems.
25 3/ Correct some typos in documentation.
1726
1827 Changes in v21.4.0:
1928 1/ Fixed problems with timezones ready for next release of tzlocal.
00 Metadata-Version: 2.1
11 Name: pywws
2 Version: 21.4.0
2 Version: 22.9.0
33 Summary: Python software for wireless weather stations
44 Home-page: http://jim-easterbrook.github.com/pywws/
55 Author: Jim Easterbrook
66 Author-email: jim@jim-easterbrook.me.uk
77 License: GNU GPL
8 Download-URL: https://pypi.python.org/pypi/pywws/21.4.0
8 Download-URL: https://pypi.python.org/pypi/pywws/22.9.0
99 Description: .. pywws - Python software for USB Wireless Weather Stations
1010 http://github.com/jim-easterbrook/pywws
1111 Copyright (C) 2008-18 pywws contributors
121121 Classifier: Programming Language :: Python
122122 Classifier: Programming Language :: Python :: 2.7
123123 Classifier: Programming Language :: Python :: 3
124 Provides-Extra: daemon
124125 Provides-Extra: sftp
125 Provides-Extra: daemon
126126 Provides-Extra: twitter
00 # pywws - Python software for USB Wireless Weather Stations
11 # http://github.com/jim-easterbrook/pywws
2 # Copyright (C) 2008-18 pywws contributors
2 # Copyright (C) 2008-22 pywws contributors
33
44 # This program is free software; you can redistribute it and/or
55 # modify it under the terms of the GNU General Public License
207207 'pywws-version = pywws.version:main',
208208 ],
209209 },
210 install_requires = ['tzlocal'],
210 install_requires = ['python-dateutil'],
211211 extras_require = {
212212 'daemon' : ['python-daemon == 2.1.2'],
213213 'sftp' : ['paramiko', 'pycrypto'],
4242 Assumptions
4343 -----------
4444
45 There are a number of assumptions that have been made to make this work which will directly affect its useability. 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:
45 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:
4646
4747 * Clothing type, thickness
4848 * Skin area exposed to free air
0 __version__ = '21.4.0'
1 _release = '1690'
2 _commit = 'dbede59'
0 __version__ = '22.9.0'
1 _release = '1696'
2 _commit = 'e9ef20a'
88 python -m pywws.datastoretransfer filedata c:\weather_data sqlite3data d:\weather
99
1010 This can be used to convert from the default file base storage system to an
11 SQL based sorage system, or back. The tranfer will overwrite existing data
11 SQL based sorage system, or back. The transfer will overwrite existing data
1212 in place which may leave existing data in the destination if the incoming data
1313 does not overlap (i.e. source data is newer than the destination). This is a
1414 risky way to merge datastores together. Otherwise, its recommended to use the
1515 optional -c argument to ensure the destination is cleared first.
1616 You may choose the same storage module for both source and destination
17 with different directories, and this is the equivelent of simply copying the
17 with different directories, and this is the equivalent of simply copying the
1818 data but will build the underlying files from scratch. However, copying the
1919 files by hand is likely to be faster.
2020
140140 :rtype: bool
141141
142142 """
143 data = ''.join(map(chr, buf))
143 data = bytes(buf)
144144 size = len(data)
145145 if hidapi.hid_write(self.device, ctypes.c_char_p(data), size) != size:
146146 raise IOError(
5050
5151 __docformat__ = "restructuredtext en"
5252
53 from contextlib import contextmanager
54
5355 import hid
5456
5557 class USBDevice(object):
6870 def __init__(self, idVendor, idProduct):
6971 if not hid.enumerate(idVendor, idProduct):
7072 raise IOError("No weather station connected")
73 self.idVendor = idVendor
74 self.idProduct = idProduct
7175 self.hid = hid.device(idVendor, idProduct)
76
77 @contextmanager
78 def open(self):
79 try:
80 self.hid.open(self.idVendor, self.idProduct)
81 yield
82 finally:
83 self.hid.close()
7284
7385 def read_data(self, size):
7486 """Receive data from the device.
8698
8799 """
88100 result = list()
89 while size > 0:
90 count = min(size, 8)
91 buf = self.hid.read(count)
92 if len(buf) < count:
93 raise IOError(
94 'pywws.device_cython_hidapi.USBDevice.read_data failed')
95 result += buf
96 size -= count
101 with self.open():
102 while size > 0:
103 count = min(size, 8)
104 buf = self.hid.read(count)
105 if len(buf) < count:
106 raise IOError(
107 'pywws.device_cython_hidapi.USBDevice.read_data failed')
108 result += buf
109 size -= count
97110 return result
98111
99112 def write_data(self, buf):
108121 :rtype: bool
109122
110123 """
111 if self.hid.write(buf) != len(buf):
112 raise IOError(
113 'pywws.device_cython_hidapi.USBDevice.write_data failed')
124 with self.open():
125 if self.hid.write(buf) != len(buf):
126 raise IOError(
127 'pywws.device_cython_hidapi.USBDevice.write_data failed')
114128 return True
1515 # along with this program; if not, write to the Free Software
1616 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1717
18 """Routines to perform common tasks such as plotting gaphs or uploading files."""
18 """Routines to perform common tasks such as plotting graphs or uploading files."""
1919
2020 from __future__ import absolute_import
2121
4040 [logged]
4141 services = ['mqtt', 'underground']
4242
43 * To customize the MQTT message use template_txt (remove illuminace and uv if weather station does not support them)::
43 * To customize the MQTT message use template_txt (remove illuminance and uv if weather station does not support them)::
4444
4545 [mqtt]
4646 ... (as above)
00 # pywws - Python software for USB Wireless Weather Stations
11 # http://github.com/jim-easterbrook/pywws
2 # Copyright (C) 2018 pywws contributors
2 # Copyright (C) 2018-22 pywws contributors
33
44 # This program is free software; you can redistribute it and/or
55 # modify it under the terms of the GNU General Public License
2020 `Weather Underground`_ may be the oldest and best known site gathering
2121 data from amateur weather stations.
2222
23 * Create account: http://www.wunderground.com/members/signup.asp
24 * API: `<http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol>`_
23 * Create account: https://www.wunderground.com/signup
24 * API: `<https://support.weather.com/s/article/PWS-Upload-Protocol>`_
2525 * Additional dependency: http://docs.python-requests.org/
2626 * Example ``weather.ini`` configuration::
2727
3838
3939 The ``internal`` configuration setting allows you to include indoor
4040 temperature and humidity in your uploads.
41
42 Note that ``password`` is not the password you use to log in to Weather
43 Underground, it's the ``Key`` value shown on your list of devices:
44 https://www.wunderground.com/member/devices
4145
4246 Previous versions of pywws had an extra ``underground_rf`` service to
4347 use Weather Underground's "rapid fire" server for frequent uploads. Now
108108 return ts
109109
110110 def _adapt_WSStatus(status):
111 """Return integer represending WSStatus dictionary input"""
111 """Return integer representing WSStatus dictionary input"""
112112 return int(WSStatus.to_csv(status))
113113
114114 # Data type convert SQLite3 ==> Python
155155 table = ""
156156 _keycol = "idx"
157157 if len(conv) == 0:
158 raise KeyError("No coloumns are defined.")
158 raise KeyError("No columns are defined.")
159159 if _keycol not in key_list:
160 # Check that the key coloumn is present
160 # Check that the key column is present
161161 raise KeyError(
162 "Key coloumn '{}' is not in the key list".format(keycol)
162 "Key column '{}' is not in the key list".format(keycol)
163163 )
164164
165165 def __init__(self, dir_name):
184184 # as it will choose the smallest integer representation between 8-64bit,
185185 # while floats are always 64bit. Set idx as a unique integer primary
186186 # key so searches are faster, storage requirements smaller,
187 # the rowid coloumn is eliminated so there is no need for secondary
187 # the rowid column is eliminated so there is no need for secondary
188188 # indices. Suitable converters/adapters are then applied.
189189 if con.execute(
190190 """SELECT COUNT(*) FROM sqlite_master
193193 ).fetchone()[0] == 0:
194194 con.executescript(
195195 """CREATE TABLE IF NOT EXISTS {table} (
196 {keycol} INTEGER PRIMARY KEY, {coloumns} );""".format(
196 {keycol} INTEGER PRIMARY KEY, {columns} );""".format(
197197 table=table,
198198 keycol=keycol,
199 coloumns=", ".join(
199 columns=", ".join(
200200 "{} NUM".format(key)
201201 for key in conv
202202 if key != keycol
204204 )
205205 )
206206
207 # Get all coloumns from the database
207 # Get all columns from the database
208208 sql_key_list = tuple(
209209 (row["name"],row["pk"])
210210 for row in con.execute(
222222
223223 # Convert this to just a set of keys
224224 sql_key_list = set(key[0] for key in sql_key_list)
225 # Check that no coloumns are missing
225 # Check that no columns are missing
226226 if not set(conv.keys()) <= sql_key_list:
227227 raise KeyError(
228 "Mismatch between database coloumns and what was expected"
229 )
230
231 # SQL snippet which casts all coloumns to the correct data types
228 "Mismatch between database columns and what was expected"
229 )
230
231 # SQL snippet which casts all columns to the correct data types
232232 # for SELECT * type queries
233233 self.selallcols = ", ".join(
234234 '{col} AS "{col} [{conv}]"'.format(
236236 conv=conv[col]
237237 ) for col in key_list
238238 )
239 # SQL snippet which casts the key coloum to the correct data type
239 # SQL snippet which casts the key column to the correct data type
240240 # for SELECT {keycol} type queries
241241 self.selkeycol = '{keycol} AS "{keycol} [{conv}]"'.format(
242242 keycol=keycol,
267267 """
268268 # Assuming the database has been analyzed before, the stat1 table
269269 # should contain the total row count for the table as the first number
270 # in the stat coloumn from when it was last analyzed. Very fast but may
270 # in the stat column from when it was last analyzed. Very fast but may
271271 # not be up to date
272272 try:
273273 return int(self._connection.execute(
298298 "Start index is greater than the End index"
299299 )
300300 else:
301 # Substitution of the key coloumn, but the
301 # Substitution of the key column, but the
302302 # parameters themselves will be substituted by sqlite3
303303 predicate = "WHERE {} BETWEEN :start AND :stop".format(
304304 self._keycol
310310 # i.start will also be None
311311 predicate = "WHERE {} <= :stop".format(self._keycol)
312312 else:
313 # both are None, so equivelent to wanting everything
313 # both are None, so equivalent to wanting everything
314314 predicate = ""
315315 multi = True
316316 pred = {"start": i.start, "stop": i.stop}
317317 elif isinstance(i, datetime):
318 # Substitution of the key coloumn, but the
318 # Substitution of the key column, but the
319319 # parameters themselves will be substituted by sqlite3
320320 predicate = "WHERE {} = :key".format(self._keycol)
321321 multi = False
386386 items being overwritten.
387387
388388 Elements in E are assumed to be dicts containing the primary key to
389 allow the equivelent of:
389 allow the equivalent of:
390390 for k in E: D[k.primary_key] = k
391391 """
392392 key_list = self.key_list
486486 )
487487
488488 def __iter__(self):
489 """Iterates over all rows in ascending order of key coloumn"""
489 """Iterates over all rows in ascending order of key column"""
490490 for row in self._connection.execute(
491491 """SELECT {} FROM {} ORDER BY {} ASC;""".format(
492492 self.selallcols,
497497 yield dict(row)
498498
499499 def __reversed__(self):
500 """Iterates over all rows in decending order of key coloumn"""
500 """Iterates over all rows in decending order of key column"""
501501 for row in self._connection.execute(
502502 """SELECT {} FROM {} ORDER BY {} DESC;""".format(
503503 self.selallcols,
11
22 # pywws - Python software for USB Wireless Weather Stations
33 # http://github.com/jim-easterbrook/pywws
4 # Copyright (C) 2008-21 pywws contributors
4 # Copyright (C) 2008-22 pywws contributors
55
66 # This program is free software; you can redistribute it and/or
77 # modify it under the terms of the GNU General Public License
4040 import logging
4141 import sys
4242
43 import tzlocal
43 import dateutil.tz
4444
4545 from pywws.constants import DAY, HOUR
4646
4848
4949
5050 class _TimeZone(object):
51 class _UTC(datetime.tzinfo):
52 _offset = datetime.timedelta(0)
53
54 def utcoffset(self, dt):
55 return self._offset
56
57 def dst(self, dt):
58 return self._offset
59
60 def tzname(self, dt):
61 return 'UTC'
62
63
6451 def __init__(self, tz_name=None):
65 if tz_name:
66 # use a named time zone instead of system default, for testing
67 import pytz
68 self.local = pytz.timezone(tz_name)
69 else:
70 self.local = tzlocal.get_localzone()
52 self.local = dateutil.tz.gettz(tz_name)
7153 logger.info('Using timezone "{!s}"'.format(self.local))
72 self._using_pytz = hasattr(self.local, 'localize')
73 if sys.version_info >= (3, 2):
74 self.utc = datetime.timezone.utc
75 else:
76 self.utc = self._UTC()
54 self.utc = dateutil.tz.UTC
7755
7856 def local_to_utc(self, dt):
7957 """Convert a local time (with or without tzinfo) to UTC without
8058 tzinfo, as used for pywws timestamps."""
8159 if dt.tzinfo is None:
82 if self._using_pytz:
83 dt = self.local.localize(dt)
84 else:
85 dt = dt.replace(tzinfo=self.local)
60 dt = dt.replace(tzinfo=self.local)
8661 return dt.astimezone(self.utc).replace(tzinfo=None)
8762
8863 def utc_to_local(self, dt):
140115 dst = day.dst()
141116 for d in range(365):
142117 day -= DAY
143 if self._using_pytz:
144 day = self.local.normalize(day)
145118 if day.dst() == dst:
146119 continue
147120 hour = day
148121 for h in range(25):
149122 hour += HOUR
150 if self._using_pytz:
151 hour = self.local.normalize(hour)
152123 if hour.dst() == dst:
153124 yield hour
154125 break
00 # pywws - Python software for USB Wireless Weather Stations
11 # http://github.com/jim-easterbrook/pywws
2 # Copyright (C) 2008-20 pywws contributors
2 # Copyright (C) 2008-22 pywws contributors
33
44 # This program is free software; you can redistribute it and/or
55 # modify it under the terms of the GNU General Public License
710710 self._read_fixed_block(0x0020), self.lo_fix_format['current_pos'])
711711 if new_ptr == self._current_ptr:
712712 return self._current_ptr
713 if (new_ptr - self.data_start) % self.reading_len[self.ws_type]:
714 logger.error('invalid ptr value %06x', new_ptr)
715 if self._current_ptr:
716 return self._current_ptr
713717 if self._current_ptr and new_ptr != self.inc_ptr(self._current_ptr):
714718 logger.error(
715719 'unexpected ptr change %06x -> %06x', self._current_ptr, new_ptr)
00 Metadata-Version: 2.1
11 Name: pywws
2 Version: 21.4.0
2 Version: 22.9.0
33 Summary: Python software for wireless weather stations
44 Home-page: http://jim-easterbrook.github.com/pywws/
55 Author: Jim Easterbrook
66 Author-email: jim@jim-easterbrook.me.uk
77 License: GNU GPL
8 Download-URL: https://pypi.python.org/pypi/pywws/21.4.0
8 Download-URL: https://pypi.python.org/pypi/pywws/22.9.0
99 Description: .. pywws - Python software for USB Wireless Weather Stations
1010 http://github.com/jim-easterbrook/pywws
1111 Copyright (C) 2008-18 pywws contributors
121121 Classifier: Programming Language :: Python
122122 Classifier: Programming Language :: Python :: 2.7
123123 Classifier: Programming Language :: Python :: 3
124 Provides-Extra: daemon
124125 Provides-Extra: sftp
125 Provides-Extra: daemon
126126 Provides-Extra: twitter
0 tzlocal
0 python-dateutil
11
22 [daemon]
33 python-daemon==2.1.2