diff --git a/docs_src/changes.md b/docs_src/changes.md index 9d29422c..050e4abe 100644 --- a/docs_src/changes.md +++ b/docs_src/changes.md @@ -3,8 +3,18 @@ WeeWX change history ### 5.2.1 MM/DD/YYYY +Remove unnecessary `UNIQUE` index on `PRIMARY KEY` columns in SQLite, achieving +size reduction of ~10%. Existing database schemas are not modified. Users +desiring size reduction are advised to consider manually migrating. + +Fix problem that prevented `weectl database reconfigure` from working in cases +where a schema was specified. + Fix problem when importing data into a MySQL database. PR -#[1025](https://github.com/weewx/weewx/pull/1025). Thanks to user Robert! +[#1025](https://github.com/weewx/weewx/pull/1025). Thanks to user Robert! + +Fix problem that prevented `weewxd` from restarting reliably if a MySQL +connection was lost. Fixes [Issue #1036](https://github.com/weewx/weewx/pull/1036). ### 5.2.0 10/05/2025 @@ -21,14 +31,13 @@ namespace. Addresses [Issue #993](https://github.com/weewx/weewx/issues/993). The WeeWX Almanac is now extensible, allowing other astronomy packages to be used besides `pyephem`. In particular, a WeeWX extension that uses the [Skyfield](https://rhodesmill.org/skyfield/) package is available and can be -installed. See [Issue #981](https://github.com/weewx/weewx/issues/981) and [PR -#988](https://github.com/weewx/weewx/pull/988). Thanks to user Johanna! +installed. See [Issue #981](https://github.com/weewx/weewx/issues/981) +and [PR #988](https://github.com/weewx/weewx/pull/988). Thanks to user Johanna! Fix LOGNAME bug in the weewx-multi sysV script. Thanks to Glenn McKechnie. -Added `illuminance` to the `wview_extended` schema. See [Issue -#992](https://github.com/weewx/weewx/issues/991) and [PR -#992](https://github.com/weewx/weewx/pull/992/files). Thanks to user Jeremy! +Added `illuminance` to the `wview_extended` schema. See [Issue #992](https://github.com/weewx/weewx/issues/991) +and [PR #992](https://github.com/weewx/weewx/pull/992/files). Thanks to user Jeremy! Fix typo that causes phantom values of `soilMoist3` to appear with VantageVue stations. @@ -52,15 +61,13 @@ Ben Cotton! In the Cumulus import code, the prefix `cur_` is used to signify a current value for most observation types. However, there was one exception: `curr_in_temp`. The utility and documentation have been changed to use `cur_in_temp` (one -'`r`'), making all types consistent. Fixes [Issue -#1006](https://github.com/weewx/weewx/issues/1006). +'`r`'), making all types consistent. Fixes [Issue #1006](https://github.com/weewx/weewx/issues/1006). Fix a problem caused by an assumption that delta times are always in seconds. Fixes issue [Issue #1009](https://github.com/weewx/weewx/issues/1009). Fix bug that prevented arbitrary types from being used with `weectl database -add-column`. Fixes issue [Issue -#1007](https://github.com/weewx/weewx/issues/1007). +add-column`. Fixes issue [Issue #1007](https://github.com/weewx/weewx/issues/1007). Fix bug that prevented MySQL and MariaDB versions greater than 10.0 from working. Fixes issue [Issue #1010](https://github.com/weewx/weewx/issues/1010). diff --git a/docs_src/upgrade.md b/docs_src/upgrade.md index 1f71eb78..67a1205e 100644 --- a/docs_src/upgrade.md +++ b/docs_src/upgrade.md @@ -124,6 +124,8 @@ directly underneath. When you're done, it should look something like this: +Finally, `weewx.restx.StdWOWBE` should be added into `restful_services`. + ### Luminosity and Illuminance diff --git a/docs_src/usersguide/mysql-mariadb.md b/docs_src/usersguide/mysql-mariadb.md index 2b2c7554..b6d14eb5 100644 --- a/docs_src/usersguide/mysql-mariadb.md +++ b/docs_src/usersguide/mysql-mariadb.md @@ -91,3 +91,15 @@ again assuming user `weewx` with password `weewx`. Adjust as necessary. CREATE USER 'weewx'@'localhost' IDENTIFIED BY 'weewx'; GRANT select, update, create, delete, insert, alter, drop ON weewx.* TO weewx@localhost; ``` + +### 5. Make sure MySQL/MariaDB starts before WeeWX + +Locate your WeeWX service file. Depending on your installation method, it will +located at either `/lib/systemd/system/weewx.service` or `/etc/systemd/system/weewx.service`). +Under the `[Unit]` section, add the following lines: + +```ini +After=mariadb.service mysqld.service +Wants=mariadb.service mysqld.service +``` +This will ensure that MySQL/MariaDB starts before WeeWX. \ No newline at end of file diff --git a/src/weedb/mysql.py b/src/weedb/mysql.py index 76121280..182e1486 100644 --- a/src/weedb/mysql.py +++ b/src/weedb/mysql.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2009-2024 Tom Keffer +# Copyright (c) 2009-2025 Tom Keffer # # See the file LICENSE.txt for your full rights. # @@ -8,16 +8,19 @@ import decimal try: + # Typically supplied by the "mysqlclient" package. import MySQLdb except ImportError: - # Maybe the user has "pymysql", a pure-Python version? + # Typically supplied by the "pymysql" package, a pure-Python version. import pymysql as MySQLdb - from pymysql import DatabaseError as MySQLDatabaseError + from pymysql import (DatabaseError as MySQLDatabaseError, + InterfaceError as MySQLInterfaceError) else: try: from MySQLdb import DatabaseError as MySQLDatabaseError except ImportError: - from _mysql_exceptions import DatabaseError as MySQLDatabaseError + from _mysql_exceptions import (DatabaseError as MySQLDatabaseError, + InterfaceError as MySQLInterfaceError) from weeutil.weeutil import to_bool, natural_compare import weedb @@ -60,6 +63,8 @@ def guard(fn): # Default exception is weedb.DatabaseError klass = exception_map.get(errno, weedb.DatabaseError) raise klass(e) + except MySQLInterfaceError as e: + raise weedb.DisconnectError(e) return guarded_fn diff --git a/src/weedb/sqlite.py b/src/weedb/sqlite.py index 8118ec5d..8779e348 100644 --- a/src/weedb/sqlite.py +++ b/src/weedb/sqlite.py @@ -268,7 +268,7 @@ class Cursor(sqlite3.Cursor, weedb.Cursor): if obs_name in column_names: continue no_null_str = " NOT NULL" if no_null else "" - pk_str = " UNIQUE PRIMARY KEY" if pk else "" + pk_str = " PRIMARY KEY" if pk else "" default_str = " DEFAULT %s" % default if default is not None else "" create_list.append("`%s` %s%s%s%s" % (obs_name, obs_type, no_null_str, pk_str, default_str)) diff --git a/src/weedb/tests/check_mysql.py b/src/weedb/tests/check_mysql.py index 723be70f..317364e1 100644 --- a/src/weedb/tests/check_mysql.py +++ b/src/weedb/tests/check_mysql.py @@ -150,7 +150,7 @@ class TestMySQL(unittest.TestCase): with Cursor(user='weewx1', password='weewx1') as cursor: cursor.execute("CREATE DATABASE test_weewx1") cursor.execute("CREATE TABLE test_weewx1.test1 " - "( dateTime INTEGER NOT NULL UNIQUE PRIMARY KEY, col1 int, col2 int)") + "( dateTime INTEGER NOT NULL PRIMARY KEY, col1 int, col2 int)") cursor.execute("INSERT INTO test_weewx1.test1 " "(dateTime, col1, col2) VALUES (1, 10, 20)") with self.assertRaises(IntegrityError) as e: diff --git a/src/weedb/tests/check_sqlite.py b/src/weedb/tests/check_sqlite.py index d657eb78..119b7883 100644 --- a/src/weedb/tests/check_sqlite.py +++ b/src/weedb/tests/check_sqlite.py @@ -100,7 +100,7 @@ class TestSqlite3(unittest.TestCase): def test_duplicate_key(self): with Cursor(sqdb1) as cursor: - cursor.execute("CREATE TABLE test1 ( dateTime INTEGER NOT NULL UNIQUE PRIMARY KEY, col1 int, col2 int)") + cursor.execute("CREATE TABLE test1 ( dateTime INTEGER NOT NULL PRIMARY KEY, col1 int, col2 int)") cursor.execute("INSERT INTO test1 (dateTime, col1, col2) VALUES (1, 10, 20)") with self.assertRaises(IntegrityError) as e: cursor.execute("INSERT INTO test1 (dateTime, col1, col2) VALUES (1, 30, 40)") diff --git a/src/weedb/tests/test_errors.py b/src/weedb/tests/test_errors.py index 363f6da8..ab336c72 100644 --- a/src/weedb/tests/test_errors.py +++ b/src/weedb/tests/test_errors.py @@ -180,7 +180,7 @@ class Common(unittest.TestCase): weedb.create(db_dict) connect = weedb.connect(db_dict) cursor = connect.cursor() - cursor.execute("CREATE TABLE test1 ( dateTime INTEGER NOT NULL UNIQUE PRIMARY KEY, col1 int, col2 int)") + cursor.execute("CREATE TABLE test1 ( dateTime INTEGER NOT NULL PRIMARY KEY, col1 int, col2 int)") cursor.execute("INSERT INTO test1 (dateTime, col1, col2) VALUES (1, 10, 20)") with self.assertRaises(weedb.IntegrityError) as e: cursor.execute("INSERT INTO test1 (dateTime, col1, col2) VALUES (1, 30, 40)") diff --git a/src/weedb/tests/test_weedb.py b/src/weedb/tests/test_weedb.py index 29811498..3f7f53b7 100644 --- a/src/weedb/tests/test_weedb.py +++ b/src/weedb/tests/test_weedb.py @@ -48,10 +48,10 @@ class Common(unittest.TestCase): weedb.create(self.db_dict) with weedb.connect(self.db_dict) as _connect: with weedb.Transaction(_connect) as _cursor: - _cursor.execute("CREATE TABLE test1 (dateTime INTEGER NOT NULL UNIQUE PRIMARY KEY," + _cursor.execute("CREATE TABLE test1 (dateTime INTEGER NOT NULL PRIMARY KEY," " min REAL, mintime INTEGER, max REAL, maxtime INTEGER, sum REAL," " count INTEGER, descript CHAR(20));") - _cursor.execute("CREATE TABLE test2 (dateTime INTEGER NOT NULL UNIQUE PRIMARY KEY," + _cursor.execute("CREATE TABLE test2 (dateTime INTEGER NOT NULL PRIMARY KEY," " min REAL, mintime INTEGER, max REAL, maxtime INTEGER, sum REAL, " "count INTEGER, descript CHAR(20));") for irec in range(20): @@ -151,7 +151,7 @@ class Common(unittest.TestCase): with weedb.connect(self.db_dict) as _connect: with _connect.cursor() as _cursor: _cursor.execute( - "CREATE TABLE test1 (dateTime INTEGER NOT NULL UNIQUE PRIMARY KEY, x REAL )") + "CREATE TABLE test1 (dateTime INTEGER NOT NULL PRIMARY KEY, x REAL )") # Now start the transaction _connect.begin() @@ -176,7 +176,7 @@ class Common(unittest.TestCase): # create the table outside the transaction. We're not as concerned about a # transaction failing when creating a table, because it only happens the first time # weewx starts up. - _connect.execute("CREATE TABLE test1 (dateTime INTEGER NOT NULL UNIQUE PRIMARY KEY, " + _connect.execute("CREATE TABLE test1 (dateTime INTEGER NOT NULL PRIMARY KEY, " "x REAL );") # We're going to trigger the rollback by raising a bogus exception. diff --git a/src/weewx/manager.py b/src/weewx/manager.py index e12a9149..2b9ee6a6 100644 --- a/src/weewx/manager.py +++ b/src/weewx/manager.py @@ -65,9 +65,9 @@ import weedb import weeutil.config import weeutil.weeutil import weewx.accum -import weewx.units import weewx.xtypes from weeutil.weeutil import timestamp_to_string, to_int, TimeSpan +from weewx.units import GenWithConvert log = logging.getLogger(__name__) @@ -708,8 +708,7 @@ def reconfig(old_db_dict, new_db_dict, new_unit_system=None, new_schema=None, dr new_schema = weewx.schemas.wview_extended.schema with Manager.open_with_create(new_db_dict, schema=new_schema) as new_archive: # Wrap the input generator in a unit converter. - record_generator = weewx.units.GenWithConvert(old_archive.genBatchRecords(), - new_unit_system) + record_generator = GenWithConvert(old_archive.genBatchRecords(), new_unit_system) if not dry_run: # This is very fast because it is done in a single transaction context: new_archive.addRecord(record_generator) @@ -1017,7 +1016,7 @@ class DaySummaryManager(Manager): # Schemas used by the daily summaries: day_schemas = { 'scalar': [ - ('dateTime', 'INTEGER NOT NULL UNIQUE PRIMARY KEY'), + ('dateTime', 'INTEGER NOT NULL PRIMARY KEY'), ('min', 'REAL'), ('mintime', 'INTEGER'), ('max', 'REAL'), @@ -1028,7 +1027,7 @@ class DaySummaryManager(Manager): ('sumtime', 'INTEGER') ], 'vector': [ - ('dateTime', 'INTEGER NOT NULL UNIQUE PRIMARY KEY'), + ('dateTime', 'INTEGER NOT NULL PRIMARY KEY'), ('min', 'REAL'), ('mintime', 'INTEGER'), ('max', 'REAL'), @@ -1048,7 +1047,7 @@ class DaySummaryManager(Manager): # SQL statements used by the metadata in the daily summaries. meta_create_str = "CREATE TABLE %s_day__metadata (name CHAR(20) NOT NULL " \ - "UNIQUE PRIMARY KEY, value TEXT);" + "PRIMARY KEY, value TEXT);" meta_replace_str = "REPLACE INTO %s_day__metadata VALUES(?, ?)" meta_select_str = "SELECT value FROM %s_day__metadata WHERE name=?" diff --git a/src/weewx/schemas/wview.py b/src/weewx/schemas/wview.py index 89d07967..7d0663fb 100644 --- a/src/weewx/schemas/wview.py +++ b/src/weewx/schemas/wview.py @@ -21,7 +21,7 @@ # with V4, a new style was added, which allows schema for the daily summaries # to be expressed explicitly. # ============================================================================= -schema = [('dateTime', 'INTEGER NOT NULL UNIQUE PRIMARY KEY'), +schema = [('dateTime', 'INTEGER NOT NULL PRIMARY KEY'), ('usUnits', 'INTEGER NOT NULL'), ('interval', 'INTEGER NOT NULL'), ('barometer', 'REAL'), diff --git a/src/weewx/schemas/wview_extended.py b/src/weewx/schemas/wview_extended.py index 3df37350..9057cdee 100644 --- a/src/weewx/schemas/wview_extended.py +++ b/src/weewx/schemas/wview_extended.py @@ -13,7 +13,7 @@ # ============================================================================= # NB: This schema is specified using the WeeWX V4 "new-style" schema. # ============================================================================= -table = [('dateTime', 'INTEGER NOT NULL UNIQUE PRIMARY KEY'), +table = [('dateTime', 'INTEGER NOT NULL PRIMARY KEY'), ('usUnits', 'INTEGER NOT NULL'), ('interval', 'INTEGER NOT NULL'), ('altimeter', 'REAL'), diff --git a/src/weewx/schemas/wview_small.py b/src/weewx/schemas/wview_small.py index 7ae21f78..0b6b4f96 100644 --- a/src/weewx/schemas/wview_small.py +++ b/src/weewx/schemas/wview_small.py @@ -14,7 +14,7 @@ # ============================================================================= # NB: This schema is specified using the WeeWX V4 "new-style" schema. # ============================================================================= -table = [('dateTime', 'INTEGER NOT NULL UNIQUE PRIMARY KEY'), +table = [('dateTime', 'INTEGER NOT NULL PRIMARY KEY'), ('usUnits', 'INTEGER NOT NULL'), ('interval', 'INTEGER NOT NULL'), ('altimeter', 'REAL'), diff --git a/src/weewx/tests/test_database.py b/src/weewx/tests/test_database.py index 358534f6..f6af1ebf 100644 --- a/src/weewx/tests/test_database.py +++ b/src/weewx/tests/test_database.py @@ -22,7 +22,7 @@ weeutil.logger.setup('weetest_database') archive_sqlite = {'database_name': '/var/tmp/weewx_test/weedb.sdb', 'driver':'weedb.sqlite'} archive_mysql = {'database_name': 'test_weedb', 'user':'weewx1', 'password':'weewx1', 'driver':'weedb.mysql'} -archive_schema = [('dateTime', 'INTEGER NOT NULL UNIQUE PRIMARY KEY'), +archive_schema = [('dateTime', 'INTEGER NOT NULL PRIMARY KEY'), ('usUnits', 'INTEGER NOT NULL'), ('interval', 'INTEGER NOT NULL'), ('barometer', 'REAL'), diff --git a/src/weewx/tests/tst_schema.py b/src/weewx/tests/tst_schema.py index 0b6965f2..237a60e9 100644 --- a/src/weewx/tests/tst_schema.py +++ b/src/weewx/tests/tst_schema.py @@ -3,7 +3,7 @@ # # See the file LICENSE.txt for your full rights. # -table = [('dateTime', 'INTEGER NOT NULL UNIQUE PRIMARY KEY'), +table = [('dateTime', 'INTEGER NOT NULL PRIMARY KEY'), ('usUnits', 'INTEGER NOT NULL'), ('interval', 'INTEGER NOT NULL'), ('altimeter', 'REAL'), diff --git a/src/weewx_data/skins/Seasons/lang/de.conf b/src/weewx_data/skins/Seasons/lang/de.conf index 82fbce9c..0e568b62 100644 --- a/src/weewx_data/skins/Seasons/lang/de.conf +++ b/src/weewx_data/skins/Seasons/lang/de.conf @@ -71,7 +71,7 @@ unit_system = metricwx lightning_distance = Blitzentfernung lightning_strike_count = Blitzanzahl luminosity = Helligkeit - outHumidity = Luftfeuchte + outHumidity = Außenluftfeuchte outTemp = Außentemperatur pressure = abs. Luftdruck # QFE pressureRate = Luftdruckänderung @@ -96,7 +96,7 @@ unit_system = metricwx windgustvec = Böen-Vektor windrun = Windverlauf windSpeed = Windgeschwindigkeit - windvec = Wind-Vektor + windvec = Windvektor # used in Seasons skin but not defined feel = gefühlte Temperatur @@ -109,7 +109,7 @@ unit_system = metricwx rainBatteryStatus = Regenmesser referenceVoltage = Referenz rxCheckPercent = Signalqualität - supplyVoltage = Versorgung + supplyVoltage = Versorgungsspannung txBatteryStatus = Übertrager windBatteryStatus = Anemometer batteryStatus1 = Batterie1 diff --git a/src/weewx_data/skins/Seasons/lang/no.conf b/src/weewx_data/skins/Seasons/lang/no.conf index b054f656..3ca46162 100644 --- a/src/weewx_data/skins/Seasons/lang/no.conf +++ b/src/weewx_data/skins/Seasons/lang/no.conf @@ -155,7 +155,7 @@ unit_system = metricwx [Almanac] # The labels to be used for the phases of the moon: - moon_phases = Nymåne, Voksende månesigd, Voksende halvmåne, Voksende fullmåne, Fullmåne, Minkende fullmåne, Minkende halvmåne, Minkende månesigd + moon_phases = Nymåne, Voksende sigd, Første kvarter, Voksende måne, Fullmåne, Avtakende måne, Siste kvarter, Avtakende sigd [Texts] "About this station" = "Om denne stasjonen" diff --git a/src/weewx_data/skins/Standard/lang/de.conf b/src/weewx_data/skins/Standard/lang/de.conf index 87ae422d..92fc708f 100644 --- a/src/weewx_data/skins/Standard/lang/de.conf +++ b/src/weewx_data/skins/Standard/lang/de.conf @@ -48,7 +48,7 @@ interval = Intervall lightning_distance = Blitzentfernung lightning_strike_count = Blitzanzahl - outHumidity = Luftfeuchte + outHumidity = Außenluftfeuchte outTemp = Außentemperatur pressure = abs. Luftdruck # QFE pressureRate = Luftdruckänderung @@ -65,7 +65,7 @@ windgustvec = Böen-Vektor windrun = Windverlauf windSpeed = Windgeschwindigkeit - windvec = Wind-Vektor + windvec = Windvektor # used in Seasons skin but not defined feel = gefühlte Temperatur @@ -78,7 +78,7 @@ rainBatteryStatus = Regenmesser referenceVoltage = Referenz rxCheckPercent = Signalqualität - supplyVoltage = Versorgung + supplyVoltage = Versorgungsspannung txBatteryStatus = Übertrager windBatteryStatus = Anemometer diff --git a/src/weewx_data/skins/Standard/lang/no.conf b/src/weewx_data/skins/Standard/lang/no.conf index 300feb41..03c67537 100644 --- a/src/weewx_data/skins/Standard/lang/no.conf +++ b/src/weewx_data/skins/Standard/lang/no.conf @@ -44,7 +44,7 @@ unit_system = metricwx [[Ordinates]] # Ordinal directions. The last one should be for no wind direction - directions = N, NNE, NØ, ØNØ, Ø, ØSØ, SØ, SSØ, S, SSV, SV, VSV, V, VNV, NV, NNV, N/A + directions = N, NNØ, NØ, ØNØ, Ø, ØSØ, SØ, SSØ, S, SSV, SV, VSV, V, VNV, NV, NNV, N/A [Labels] @@ -111,7 +111,7 @@ unit_system = metricwx [Almanac] # The labels to be used for the phases of the moon: - moon_phases = Nymåne, Voksende månesigd, Halvmåne første kvarter, Voksende måne (ny), Fullmåne, Minkende måne (ne), Halvmåne siste kvarter, Minkende månesigd + moon_phases = Nymåne, Voksende sigd, Første kvarter, Voksende måne, Fullmåne, Avtakende måne, Siste kvarter, Avtakende sigd [Texts] "7-day" = "7-dager" diff --git a/src/weewx_data/util/systemd/weewx.service b/src/weewx_data/util/systemd/weewx.service index ff16cbab..df3f8613 100644 --- a/src/weewx_data/util/systemd/weewx.service +++ b/src/weewx_data/util/systemd/weewx.service @@ -8,6 +8,14 @@ After=time-sync.target Wants=network-online.target After=network-online.target +# If you are using MySQL uncomment the following lines: +# After=mysqld.service +# Wants=mysqld.service + +# If you are using MariaDB uncomment the following lines: +# After=mariadb.service +# Wants=mariadb.service + [Service] ExecStart=WEEWX_PYTHON WEEWXD WEEWX_CFGDIR/weewx.conf StandardOutput=null