From f0d635e190a2e6f873825254d335c545d4a6eee9 Mon Sep 17 00:00:00 2001 From: Dennis Siemensma Date: Sat, 18 Mar 2017 18:28:03 +0100 Subject: [PATCH] Merge for v1.6 release! --- README.md | 26 +- docs/api.rst | 43 +- docs/changelog.rst | 50 + docs/conf.py | 6 +- docs/contributing.rst | 8 +- docs/credits.rst | 14 +- docs/faq.rst | 10 +- docs/index.rst | 2 + docs/installation.rst | 82 +- docs/intro.rst | 2 +- docs/locale/nl/LC_MESSAGES/api.mo | Bin 4985 -> 5116 bytes docs/locale/nl/LC_MESSAGES/api.po | 122 +- docs/locale/nl/LC_MESSAGES/changelog.mo | Bin 4672 -> 4568 bytes docs/locale/nl/LC_MESSAGES/changelog.po | 1106 ++++++++++------- docs/locale/nl/LC_MESSAGES/contributing.mo | Bin 2064 -> 2041 bytes docs/locale/nl/LC_MESSAGES/contributing.po | 16 +- docs/locale/nl/LC_MESSAGES/credits.mo | Bin 1251 -> 1011 bytes docs/locale/nl/LC_MESSAGES/credits.po | 54 +- docs/locale/nl/LC_MESSAGES/faq.mo | Bin 18292 -> 18585 bytes docs/locale/nl/LC_MESSAGES/faq.po | 437 +++---- docs/locale/nl/LC_MESSAGES/installation.mo | Bin 26329 -> 26613 bytes docs/locale/nl/LC_MESSAGES/installation.po | 939 +++++--------- docs/locale/nl/LC_MESSAGES/intro.mo | Bin 2934 -> 2459 bytes docs/locale/nl/LC_MESSAGES/intro.po | 35 +- docs/locale/nl/LC_MESSAGES/screenshots.mo | Bin 5178 -> 4274 bytes docs/locale/nl/LC_MESSAGES/screenshots.po | 149 +-- docs/locale/nl/LC_MESSAGES/settings.mo | Bin 0 -> 10294 bytes docs/locale/nl/LC_MESSAGES/settings.po | 386 ++++++ docs/locale/nl/LC_MESSAGES/troubleshooting.mo | Bin 0 -> 3375 bytes docs/locale/nl/LC_MESSAGES/troubleshooting.po | 107 ++ docs/screenshots.rst | 10 - docs/settings.rst | 181 +++ docs/troubleshooting.rst | 37 + dsmr_api/tests/test_api.py | 2 +- dsmr_api/views.py | 6 +- dsmr_backend/apps.py | 2 +- .../management/commands/development_reset.py | 21 + .../management/commands/dsmr_backend.py | 6 +- dsmr_backend/mixins.py | 4 +- dsmr_backend/services.py | 4 +- dsmr_backend/tests/test_backend.py | 12 +- dsmr_backup/admin.py | 23 + .../migrations/0002_settings_documentation.py | 20 + dsmr_backup/models/settings.py | 8 - dsmr_backup/services/backup.py | 2 +- dsmr_backup/services/dropbox.py | 2 +- dsmr_backup/tests/test_services.py | 2 +- dsmr_consumption/admin.py | 14 +- .../dsmr_consumption/test_dsmrreading_v5.json | 107 ++ .../migrations/0006_dsmr_firmware_v5.py | 33 + .../migrations/0007_settings_documentation.py | 23 + dsmr_consumption/models/consumption.py | 10 +- dsmr_consumption/services.py | 174 +-- dsmr_consumption/tests/test_services.py | 47 + dsmr_datalogger/admin.py | 3 +- dsmr_datalogger/dsmr.py | 1 + .../management/commands/dsmr_datalogger.py | 4 +- .../commands/dsmr_fake_datasource.py | 107 +- .../migrations/0006_dsmr_firmware_v5.py | 34 + dsmr_datalogger/models/reading.py | 77 +- dsmr_datalogger/models/settings.py | 18 +- dsmr_datalogger/models/statistics.py | 78 ++ dsmr_datalogger/services.py | 84 +- .../tests/datalogger/test_generic.py | 36 +- .../tests/datalogger/test_iskra.py | 5 +- .../tests/datalogger/test_kaifa_dsmr42.py | 4 +- .../datalogger/test_landisgyr350_dsmr40.py | 4 +- .../datalogger/test_landisgyr350_dsmr42.py | 4 +- .../test_landisgyr350_other_dsmr42.py | 4 +- dsmr_datalogger/tests/models/test_reading.py | 8 +- dsmr_datalogger/tests/models/test_settings.py | 5 +- dsmr_frontend/forms.py | 19 +- .../static/dsmr_frontend/css/dsmrreader.css | 2 +- .../dsmr_frontend/img/GitHub-Mark-32px.png | Bin 0 -> 1714 bytes .../static/dsmr_frontend/img/favicon.png | Bin 2071 -> 0 bytes .../img/favicons/android-chrome-192x192.png | Bin 0 -> 9729 bytes .../img/favicons/android-chrome-512x512.png | Bin 0 -> 23212 bytes .../img/favicons/apple-touch-icon.png | Bin 0 -> 5155 bytes .../img/favicons/browserconfig.xml | 9 + .../img/favicons/favicon-16x16.png | Bin 0 -> 1086 bytes .../img/favicons/favicon-32x32.png | Bin 0 -> 1787 bytes .../dsmr_frontend/img/favicons/favicon.ico | Bin 0 -> 15086 bytes .../dsmr_frontend/img/favicons/favicon.png | Bin 0 -> 23094 bytes .../dsmr_frontend/img/favicons/manifest.json | 18 + .../img/favicons/mstile-150x150.png | Bin 0 -> 6814 bytes .../img/favicons/safari-pinned-tab.svg | 15 + .../templates/dsmr_frontend/base.html | 22 +- .../templates/dsmr_frontend/dashboard.html | 79 +- .../templates/dsmr_frontend/statistics.html | 6 - .../templates/dsmr_frontend/status.html | 83 +- dsmr_frontend/tests/webinterface/__init__.py | 0 .../tests/webinterface/test_archive.py | 113 ++ .../tests/webinterface/test_compare.py | 80 ++ .../tests/webinterface/test_dashboard.py | 185 +++ .../tests/webinterface/test_export.py | 124 ++ .../tests/webinterface/test_generic.py | 104 ++ .../tests/webinterface/test_statistics.py | 97 ++ .../tests/webinterface/test_status.py | 135 ++ .../test_trends.py} | 7 +- dsmr_frontend/views/dashboard.py | 31 +- dsmr_frontend/views/statistics.py | 3 +- dsmr_frontend/views/status.py | 11 +- dsmr_mindergas/admin.py | 14 +- dsmr_notification/admin.py | 14 +- dsmrreader/__init__.py | 2 +- dsmrreader/config/base.py | 12 +- dsmrreader/locales/nl/LC_MESSAGES/django.mo | Bin 37879 -> 41327 bytes dsmrreader/locales/nl/LC_MESSAGES/django.po | 194 ++- dsmrreader/provisioning/requirements/base.txt | 14 +- dsmrreader/provisioning/requirements/dev.txt | 4 +- .../provisioning/requirements/mysql.txt | 2 +- .../provisioning/requirements/postgresql.txt | 2 +- dsmrreader/provisioning/requirements/test.txt | 2 +- .../provisioning/requirements/travis.txt | 2 +- pylama.ini | 1 + upgrade.sh | 5 + 116 files changed, 4180 insertions(+), 2051 deletions(-) create mode 100644 docs/locale/nl/LC_MESSAGES/settings.mo create mode 100644 docs/locale/nl/LC_MESSAGES/settings.po create mode 100644 docs/locale/nl/LC_MESSAGES/troubleshooting.mo create mode 100644 docs/locale/nl/LC_MESSAGES/troubleshooting.po create mode 100644 docs/settings.rst create mode 100644 docs/troubleshooting.rst create mode 100644 dsmr_backend/management/commands/development_reset.py create mode 100644 dsmr_backup/migrations/0002_settings_documentation.py create mode 100644 dsmr_consumption/fixtures/dsmr_consumption/test_dsmrreading_v5.json create mode 100644 dsmr_consumption/migrations/0006_dsmr_firmware_v5.py create mode 100644 dsmr_consumption/migrations/0007_settings_documentation.py create mode 100644 dsmr_datalogger/migrations/0006_dsmr_firmware_v5.py create mode 100644 dsmr_datalogger/models/statistics.py create mode 100644 dsmr_frontend/static/dsmr_frontend/img/GitHub-Mark-32px.png delete mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicon.png create mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicons/android-chrome-192x192.png create mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicons/android-chrome-512x512.png create mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicons/apple-touch-icon.png create mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicons/browserconfig.xml create mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicons/favicon-16x16.png create mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicons/favicon-32x32.png create mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicons/favicon.ico create mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicons/favicon.png create mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicons/manifest.json create mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicons/mstile-150x150.png create mode 100644 dsmr_frontend/static/dsmr_frontend/img/favicons/safari-pinned-tab.svg create mode 100644 dsmr_frontend/tests/webinterface/__init__.py create mode 100644 dsmr_frontend/tests/webinterface/test_archive.py create mode 100644 dsmr_frontend/tests/webinterface/test_compare.py create mode 100644 dsmr_frontend/tests/webinterface/test_dashboard.py create mode 100644 dsmr_frontend/tests/webinterface/test_export.py create mode 100644 dsmr_frontend/tests/webinterface/test_generic.py create mode 100644 dsmr_frontend/tests/webinterface/test_statistics.py create mode 100644 dsmr_frontend/tests/webinterface/test_status.py rename dsmr_frontend/tests/{test_webinterface.py => webinterface/test_trends.py} (98%) create mode 100755 upgrade.sh diff --git a/README.md b/README.md index 5a7cf9cda..0da8f1e14 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,29 @@ [![Build Status](https://travis-ci.org/dennissiemensma/dsmr-reader.svg?branch=master)](https://travis-ci.org/dennissiemensma/dsmr-reader) [![Coverage](https://codecov.io/github/dennissiemensma/dsmr-reader/coverage.svg?branch=master)](https://codecov.io/gh/dennissiemensma/dsmr-reader/branch/master) -[![Requirements Status](https://requires.io/github/dennissiemensma/dsmr-reader/requirements.svg?branch=master)](https://requires.io/github/dennissiemensma/dsmr-reader/requirements/?branch=master) [![Documentation Status](https://readthedocs.org/projects/dsmr-reader/badge/?version=latest)](https://dsmr-reader.readthedocs.io/en/latest/?badge=latest) +[![Requirements Status](https://requires.io/github/dennissiemensma/dsmr-reader/requirements.svg?branch=master)](https://requires.io/github/dennissiemensma/dsmr-reader/requirements/?branch=master) +# DSMR Reader Datalogger/GUI -# Documentation (English & Dutch / Nederlands) - -**English** - -See [Read The Docs, in English](https://dsmr-reader.readthedocs.io/en/latest/). Installation guide can be found there as well. +## Project mission & goals +- Have fun by reading your smart meter at home yourself! +- Provide an easy to use setup for logging your own energy consumption. +- Keeping your data for yourself (all data is stored locally and untracked as well). +- Always free to use (and open source). -**Dutch / Nederlands** -Zie [Read The Docs, in het Nederlands](https://dsmr-reader.readthedocs.io/nl/latest/). Je kunt daar ook alle installatieinstructies vinden. +## Documentation (`English` & `Nederlands`) +- `English`: See [Read The Docs, in English](https://dsmr-reader.readthedocs.io/en/latest/). Installation guide can be found there as well. +- `Nederlands`: Zie [Read The Docs, in het Nederlands](https://dsmr-reader.readthedocs.io/nl/latest/). Je kunt daar ook alle installatieinstructies vinden. -# Screenshots +## Screenshots More screenshots can be found in the documentation at [Read The Docs](https://dsmr-reader.readthedocs.io/en/latest/screenshots.html). -## Dashboard + +### Dashboard ![Dashboard](docs/_static/screenshots/dashboard.png) -## Archive + +### Archive ![Archive](docs/_static/screenshots/archive.png) diff --git a/docs/api.rst b/docs/api.rst index 2c800ac82..e3381884a 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -58,9 +58,14 @@ This allows you to insert a raw telegram, read from your meter remotely, into th Parameters ~~~~~~~~~~ + +.. note:: + + Since ``v1.6`` this call now returns ``HTTP 201`` instead of ``HTTP 200`` when successful. + - Method: ``POST`` - Data: ``telegram`` (as raw string containing all linefeeds ``\n``, and carriage returns ``\r``, as well!) -- Status code returned: ``HTTP 200`` on success, any other on failure. +- Status code returned: ``HTTP 201`` on success, any other on failure. Example ~~~~~~~ @@ -103,8 +108,8 @@ Example data={'telegram': telegram_string}, ) - # You will receive a status 200 when successful. - if response.status_code != 200: + # You will receive a status 201 when successful. + if response.status_code != 201: # Or you will find the error (hint) in the reponse body on failure. print('Error: {}'.format(response.text)) @@ -151,14 +156,15 @@ Client file in ``/home/dsmr/dsmr_datalogger_api_client.py``:: def main(): print ('Starting...') - while True: - telegram = read_telegram() - print('Read telegram', telegram) + for telegram in read_telegram(): + print('Telegram read') + print(telegram) for current_server in API_SERVERS: api_url, api_key = current_server + + print('Sending telegram to:', api_url) send_telegram(telegram, api_url, api_key) - print('Sent telegram to:', api_url) sleep(1) @@ -179,7 +185,7 @@ Client file in ``/home/dsmr/dsmr_datalogger_api_client.py``:: serial_handle.open() telegram_start_seen = False - telegram = '' + buffer = '' # Just keep fetching data until we got what we were looking for. while True: @@ -188,7 +194,7 @@ Client file in ``/home/dsmr/dsmr_datalogger_api_client.py``:: except SerialException as error: # Something else and unexpected failed. print('Serial connection failed:', error) - return + raise StopIteration() # Break out of yield. try: # Make sure weird characters are converted properly. @@ -205,12 +211,15 @@ Client file in ``/home/dsmr/dsmr_datalogger_api_client.py``:: # Delay any logging until we've seen the start of a telegram. if telegram_start_seen: - telegram += data + buffer += data # Telegrams ends with '!' AND we saw the start. We should have a complete telegram now. if data.startswith('!') and telegram_start_seen: - serial_handle.close() - return telegram + yield buffer + + # Reset the flow again. + telegram_start_seen = False + buffer = '' def send_telegram(telegram, api_url, api_key): @@ -221,16 +230,16 @@ Client file in ``/home/dsmr/dsmr_datalogger_api_client.py``:: data={'telegram': telegram}, ) - # You will receive a status 200 when successful. - if response.status_code != 200: - # Or you will find the error (hint) in the response body on failure. - print('[!] Error: {}'.format(response.text)) - + # Old versions of DSMR-reader return 200, new ones 201. + if response.status_code not in (200, 201): + # Or you will find the error (hint) in the reponse body on failure. + print('API error: {}'.format(response.text)) if __name__ == '__main__': main() + Supervisor config in ``/etc/supervisor/conf.d/dsmr-client.conf``:: [program:dsmr_client_datalogger] diff --git a/docs/changelog.rst b/docs/changelog.rst index bfd3fa4be..aef11395b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -18,6 +18,56 @@ Please make sure you have a fresh **database backup** before upgrading! Upgradin +v1.6.0 - 2017-03-18 +^^^^^^^^^^^^^^^^^^^ + +.. warning:: + + Support for ``MySQL`` has been **deprecated** since ``DSMR-reader v1.6`` and will be discontinued completely in a later release. + Please use a PostgreSQL database instead. Users already running MySQL will be supported in easily migrating to PostgreSQL in the future. + +.. note:: + + **Change in API:** + The telegram creation API now returns an ``HTTP 201`` response when successful. + An ``HTTP 200`` was returned in former versions. + :doc:`View API docs`. + + +**Tickets resolved in this release:** + +- [`#221 `_] Support for DSMR-firmware v5.0. +- [`#237 `_] Redesign: Status page. +- [`#249 `_] Req: Add iOS icon for Bookmark. +- [`#232 `_] Docs: Explain settings/options. +- [`#260 `_] Add link to readthedocs in Django for Dropbox instructions. +- [`#211 `_] API request should return HTTP 201 instead of HTTP 200. +- [`#191 `_] Deprecate MySQL support. +- [`#251 `_] Buienradar Uncaught exception. +- [`#257 `_] Requirements update (February 2017). +- [`#274 `_] Requirements update (March 2017). + + + +v1.5.5 - 2017-01-19 +^^^^^^^^^^^^^^^^^^^ + +**Tickets resolved in this release:** + +- Remove readonly restriction for editing statistics in admin interface (`#242 `_). + + + +v1.5.4 - 2017-01-12 +^^^^^^^^^^^^^^^^^^^ + +**Tickets resolved in this release:** + +- Improve datalogger for DSMR v5.0 (`#212 `_). +- Fixed another bug in MinderGas API client implementation (`#228 `_). + + + v1.5.5 - 2017-01-19 ^^^^^^^^^^^^^^^^^^^ diff --git a/docs/conf.py b/docs/conf.py index ffaa0aa5e..f90f26756 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -56,9 +56,9 @@ # built documents. # # The short X.Y version. -version = '1.5' +version = '1.x' # The full version, including alpha/beta/rc tags. -release = '1.5.0' +release = '1.x' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -298,4 +298,4 @@ #texinfo_no_detailmenu = False locale_dirs = ['locale/'] # path is example but recommended. -gettext_compact = True +gettext_compact = False diff --git a/docs/contributing.rst b/docs/contributing.rst index 1ea25f5c3..e3f2d4693 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -3,10 +3,10 @@ Contributing Would you like to contribute or help this project in any way? -Feedback --------- -All feedback and any input is, as always, very much appreciated! -It doesn't matter whether you run into problems getting started in this guide or just want to get in touch, just fire away! +Feedback / Bugs / Contact +------------------------- +Any feedback or input is appreciated. +It doesn't matter whether you run into problems or just want to get in touch, just fire away! .. seealso:: diff --git a/docs/credits.rst b/docs/credits.rst index 450708286..6998b1dbe 100644 --- a/docs/credits.rst +++ b/docs/credits.rst @@ -1,5 +1,5 @@ -Credits -======= +Credits / Hall of Fame +====================== Special thanks for supplying code contributions @@ -25,9 +25,9 @@ Listed in any order, sorted by name. - "`WatskeBart `_" -Software --------- -Please note and respect their licences, if any, as well. +Software used +------------- +Please note and respect their licences as well, if any. Credits to the following software and projects: - `Raspbian `_ @@ -47,7 +47,9 @@ Please note and respect their licences, if any, as well. - `Director Responsive Admin `_ -- `Favicon `_ +- Favicon made by `Freepik `_ from `flaticon.com `_ + +- `Real Favicon Generator `_ - `Bootstrap-datepicker `_ diff --git a/docs/faq.rst b/docs/faq.rst index e91200e37..ae48151c3 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -15,10 +15,10 @@ Every once in a while there may be updates. Since ``v1.5`` you can also easily c Before updating, **please make sure you have a recent backup of your database**! :doc:`More information about backups can be found here`. -You can update your application to the latest version by executing **deploy.sh**, located in the root of the project. +You can update your application to the latest version by executing **upgrade.sh**, located in the root of the project. Make sure to execute it while logged in as the ``dsmr`` user:: - ./deploy.sh + ./upgrade.sh It will make sure to check, fetch and apply any changes released. Summary of deployment script steps: @@ -189,6 +189,8 @@ Only want to restore the database? - Stop the application first with ``sudo supervisorctl stop all``. This will disconnect it from the database as well. +- Importing the data could take a long time. It took MySQL 15 minutes to import nearly 3 million readings, from a compressed backup, on a RaspberryPi 3. + For **PostgreSQL** restores:: sudo sudo -u postgres dropdb dsmrreader @@ -209,12 +211,12 @@ For **MySQL** restores:: sudo mysqladmin drop dsmrreader # Either restore an uncompressed (.sql) backup: - cat | sudo mysql -D dsmrreader --defaults-file=/etc/mysql/debian.cnf + cat | sudo mysql --defaults-file=/etc/mysql/debian.cnf -D dsmrreader # OR # Restore a compressed (.gz) backup with: - zcat | sudo mysql -D dsmrreader --defaults-file=/etc/mysql/debian.cnf + zcat | sudo mysql --defaults-file=/etc/mysql/debian.cnf -D dsmrreader - Start the application again with ``sudo supervisorctl start all``. diff --git a/docs/index.rst b/docs/index.rst index 7f38182c4..00fdeb3f7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,7 +8,9 @@ DSMR Reader's documentation screenshots installation application + settings api + troubleshooting faq changelog contributing diff --git a/docs/installation.rst b/docs/installation.rst index f00795df6..d3478520b 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -14,14 +14,18 @@ Dependencies & requirements --------------------------- - **RaspberryPi 2 or 3** - - The RaspberryPi 1 tends to be **too slow** for this project, as it requires multi core processing. - .. note:: - **Alternative #1**: You can also run it on any server near your smart meter, as long as it satisfies the other requirements. - **Alternative #2**: The application supports receiving P1 telegrams using an API, so you can also run it on a server outside your home. (:doc:`API DOCS`) +.. warning:: + + The RaspberryPi 1 tends to be **too slow** for this project, as it requires multi core processing. + + You can however run just the datalogger client on an old RaspberryPi, :doc:`see for the API for a howto and example scripts`. + - **Raspbian OS** - Recommended and tested with, but any OS satisfying the requirements should do fine. @@ -32,13 +36,16 @@ Dependencies & requirements Support for ``Python 3.3`` has been **discontinued** since ``DSMR-reader v1.5`` (due to Django). -- **PostgreSQL 9+ or MySQL / MariaDB 5.5+** +- **PostgreSQL 9+ database** + +.. warning:: - - I **highly recommend** ``PostgreSQL`` due to builtin support for timezones. + Support for ``MySQL`` has been **deprecated** since ``DSMR-reader v1.6`` and will be discontinued completely in a later release. + Please use a PostgreSQL database instead. Users already running MySQL will be supported in migrating at a later moment. - **Smart Meter** with support for **at least DSMR 4.x+** and a **P1 telegram port** - - Tested so far with Landis+Gyr E350, Kaifa. Telegram port looks like an RJ11 (phone) socket. + - Tested so far with Landis+Gyr E350, Kaifa. - **Minimal 1 GB of disk space on RaspberryPi (card)** (for application installation & virtualenv). @@ -54,24 +61,21 @@ Dependencies & requirements - It just really helps if you know what you are doing. -1. Database backend -------------------- - -The application stores by default all readings taken from the serial cable. Depending on your needs, you can choose for either (Option A.) **PostgreSQL** (Option B.) **MySQL/MariaDB**. - -.. note:: +1. Database backend (PostgreSQL) +-------------------------------- - If you have no idea what to choose, I generally advise to pick PostgreSQL, as it has builtin support for (local) timezone handling (required for daylight saving time transitions). +The application stores by default all readings taken from the serial cable. +There is support for **PostgreSQL**, and there used to be support for **MySQL/MariaDB** as well. +The latter is currently deprecated by this project and support will be discontinued in a future release. -(Option A.) PostgreSQL -^^^^^^^^^^^^^^^^^^^^^^ Install PostgreSQL, ``postgresql-server-dev-all`` is required for the virtualenv installation later in this guide. - Install database:: sudo apt-get install -y postgresql postgresql-server-dev-all -Does Postgres not start due to locales? Try: ``dpkg-reconfigure locales``. Still no luck? Try editing ``/etc/environment``, add ``LC_ALL="en_US.utf-8"`` and reboot. +Does Postgres not start due to locales? Try: ``dpkg-reconfigure locales``. +Still no luck? Try editing ``/etc/environment``, add ``LC_ALL="en_US.utf-8"`` and reboot. (!) Ignore any '*could not change directory to "/root": Permission denied*' errors for the following three commands. @@ -99,10 +103,17 @@ Does Postgres not start due to locales? Try: ``dpkg-reconfigure locales``. Stil zcat | sudo sudo -u postgres psql dsmrreader +Now continue at chapter 2 below (Dependencies). -(Option B.) MySQL/MariaDB +(Legacy) MySQL/MariaDB ^^^^^^^^^^^^^^^^^^^^^^^^^ -Install MariaDB. You can also choose to install the closed source MySQL, as they should be interchangeable anyway. ``libmysqlclient-dev`` is required for the virtualenv installation later in this guide. +.. warning:: + + Support for the MySQL database backend is deprecated and will be removed in a later release. + Please use a PostgreSQL database instead. Users already running MySQL will be supported in migrating at a later moment. + +Install MariaDB. You can also choose to install the closed source MySQL, as they should be interchangeable anyway. +``libmysqlclient-dev`` is required for the virtualenv installation later in this guide. - Install database:: @@ -110,7 +121,7 @@ Install MariaDB. You can also choose to install the closed source MySQL, as they - Create database:: - sudo mysqladmin create dsmrreader + sudo mysqladmin --defaults-file=/etc/mysql/debian.cnf create dsmrreader - Create database user:: @@ -122,7 +133,7 @@ Install MariaDB. You can also choose to install the closed source MySQL, as they - Flush privileges to activate them:: - sudo mysqladmin reload --defaults-file=/etc/mysql/debian.cnf + sudo mysqladmin --defaults-file=/etc/mysql/debian.cnf reload .. note:: @@ -130,11 +141,11 @@ Install MariaDB. You can also choose to install the closed source MySQL, as they Restore an uncompressed (``.sql``) backup with:: - cat | sudo mysql -D dsmrreader --defaults-file=/etc/mysql/debian.cnf + cat | sudo mysql --defaults-file=/etc/mysql/debian.cnf -D dsmrreader Or restore a compressed (``.gz``) backup with:: - zcat | sudo mysql -D dsmrreader --defaults-file=/etc/mysql/debian.cnf + zcat | sudo mysql --defaults-file=/etc/mysql/debian.cnf -D dsmrreader 2. Dependencies @@ -143,7 +154,8 @@ Now you'll have to install several utilities, required for the Nginx webserver, sudo apt-get install -y nginx supervisor git python3 python3-pip python3-virtualenv virtualenvwrapper -Install ``cu``. The CU program allows easy testing for your DSMR serial connection. It's very basic but also very effective to simply test whether your serial cable setup works properly. :: +Install ``cu``. The CU program allows easy testing for your DSMR serial connection. +It's very basic but also very effective to simply test whether your serial cable setup works properly:: sudo apt-get install -y cu @@ -255,9 +267,8 @@ Make sure you've read and executed the note above, because you'll need it for th 7. Application configuration & setup ------------------------------------ -Earlier in this guide you had to choose for either **(A.) PostgreSQL** or **(B.) MySQL/MariaDB**. Our application needs to know which backend used in order to communicate with it. - -Therefor I created two default (Django-)settings files you can copy, one for each backend. The application will also need the appropriate database client, which is not installed by default. For this I also created two ready-to-use requirements files, which will also install all other dependencies required, such as the Django framework. +The application will also need the appropriate database client, which is not installed by default. +For this I created two ready-to-use requirements files, which will also install all other dependencies required, such as the Django framework. The ``base.txt`` contains requirements which the application needs anyway, no matter which backend you've choosen. @@ -265,7 +276,7 @@ The ``base.txt`` contains requirements which the application needs anyway, no ma **Installation of the requirements below might take a while**, depending on your Internet connection, RaspberryPi speed and resources (generally CPU) available. Nothing to worry about. :] -(Option A.) PostgreSQL +PostgreSQL ^^^^^^^^^^^^^^^^^^^^^^ - Did you choose PostgreSQL? Then execute these two lines:: @@ -273,18 +284,27 @@ The ``base.txt`` contains requirements which the application needs anyway, no ma pip3 install -r dsmrreader/provisioning/requirements/base.txt -r dsmrreader/provisioning/requirements/postgresql.txt -(Option B.) MySQL/MariaDB + +Did everything install without fatal errors? If the database client refuses to install due to missing files/configs, +make sure you've installed ``postgresql-server-dev-all`` earlier in the process, when you installed the database server itself. + +Continue to chapter 8 (Bootstrapping). + +(Legacy) MySQL/MariaDB ^^^^^^^^^^^^^^^^^^^^^^^^^ +.. warning:: + + Support for the MySQL database backend is deprecated and will be removed in a later release. + Please use a PostgreSQL database instead. Users already running MySQL will be supported in migrating at a later moment. + - Or did you choose MySQL/MariaDB? Execute these two commands:: cp dsmrreader/provisioning/django/mysql.py dsmrreader/settings.py pip3 install -r dsmrreader/provisioning/requirements/base.txt -r dsmrreader/provisioning/requirements/mysql.txt - -Did everything install without fatal errors? If either of the database clients refuses to install due to missing files/configs, -make sure you've installed ``postgresql-server-dev-all`` (for **PostgreSQL**) or ``libmysqlclient-dev`` (for **MySQL**) earlier in the process, -when you installed the database server itself. +Did everything install without fatal errors? If the database client refuses to install due to missing files/configs, +make sure you've installed ``libmysqlclient-dev`` earlier in the process, when you installed the database server itself. 8. Bootstrapping diff --git a/docs/intro.rst b/docs/intro.rst index 256a56e81..765de3bc2 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -15,7 +15,7 @@ Because open-source triggers the community to collaborate even more and bring ou Languages --------- -The entire application and it's code is written in English. The entire interface however is also translated into Dutch and will be triggered depending on you browser's language preference. +The entire application and it's code is written in English. The interface is also translated into Dutch and will be triggered depending on your browser's language preference. Skill diff --git a/docs/locale/nl/LC_MESSAGES/api.mo b/docs/locale/nl/LC_MESSAGES/api.mo index 06ef8fd93f5e0540ebc38b317136ac454c07476a..4365021c731ae4b33054ce2e314086e139e712de 100644 GIT binary patch delta 889 zcmY+>OK1~87{Ku_iH$MURBL_IN1cOJBr#^AsS-p*L<@rWs1{$4C7CqAbR*eK1GO}# zfF9IBK*WN0@KOXX0r4&cPl5`fw}N=}AbJoy_@5+JI_x*UncaDOGy8kbpS^Qly(l8r zdqjG15zpXz4C7!>WHs)_5XNvlrZ9%5(TsDEM`o$6VFOR$5}w3i7Ma8XHt-W3!y6%~ z%R?ITtZo*Lt`Ql)qd0>X@Gic?J3f(db~`}-BiWkqfwdh6FhGA887lkG9OxiE!{a!^ z{3Sd=|7JvlraX<*MJhC2bYBehiCm-~MIM=@G7COHv*2UgfX^|8uh87US2Q>99W(d~ z%{o`eaugSE8h_vuoMe%67^?S++@dj#~=UYL&@MS@DrfMtOyztFm^fq?~e1RkT;FI4++@$Hva9 zWWr)d(Q!R(=TtfW|9yh@wSsn(Tg_&*>*lMac=LWx`K;E<;O9U%x!)R5Rw|u3(wqyc zP|{M?p|o|l`8xczwb1*;-?|q$>#G-?oY||J%7oT=Pv!Kq?j*D#2~St56QrVUmu%Z} w)s*e5$R?(0w&Q4B>1H%lF2&`NXM0tSSI%jU=2lA{bJNT7{0Xb|v#$~O3-!&7%m4rY delta 757 zcmX}p&ui0Q7{Ku-t?jy0YyDM!Z^6S9Y-$oGlOD#eSr;%A)09-4R}Ei!^O>iBb*$7w8L1$A5tx#S_uEIz>txQTbMz$6`ffYWGZq%BXm znP*m=@H_6uEo|W*e1xr0kvE1&idD|g-(Z(IzPIf!Ow#WoLq&EDf5gPsbPL$x`*%1) ze=;{1BF$WTxZ`ymG>64HJ*otGh%AsA$H;y0 zhs29S=3*E`eh{t3*HcBK`!hXeIB!S3B|X=6Jj-*-?%C6h>p13O#a{B)>Z|oIuxG20 zU$#8QowA*OXGG^&X=Z2Zu}+N aOQh$6+hMa7Z{!w??$!Lb;l%gyo#bBtTV8zt diff --git a/docs/locale/nl/LC_MESSAGES/api.po b/docs/locale/nl/LC_MESSAGES/api.po index ddae49f99..c5f09e584 100644 --- a/docs/locale/nl/LC_MESSAGES/api.po +++ b/docs/locale/nl/LC_MESSAGES/api.po @@ -8,16 +8,14 @@ msgid "" msgstr "" "Project-Id-Version: DSMR Reader v1.x\n" "Report-Msgid-Bugs-To: Dennis Siemensma \n" -"POT-Creation-Date: 2017-01-02 21:13+0100\n" -"PO-Revision-Date: 2017-01-02 21:24+0100\n" +"POT-Creation-Date: 2017-02-16 15:58+0100\n" +"PO-Revision-Date: 2017-01-21 14:17+0100\n" "Last-Translator: Dennis Siemensma \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.3.4\n" -"Language: nl\n" -"X-Generator: Poedit 1.8.7.1\n" #: ../../api.rst:2 msgid "API" @@ -29,12 +27,8 @@ msgid "" "allows you to run the datalogger and application separately." msgstr "" "De applicatie heeft een eenvoudige, enkele API-call voor dataloggers op " -"afstand. Hiermee kun je de datalogger en applicatie gescheiden van elkaar " -"draaien." - -#: ../../api.rst -msgid "Contents" -msgstr "Inhoud" +"afstand. Hiermee kun je de datalogger en applicatie gescheiden van elkaar" +" draaien." #: ../../api.rst:10 msgid "Configuration" @@ -46,13 +40,13 @@ msgstr "API inschakelen" #: ../../api.rst:15 msgid "" -"The API is disabled by default in the application. You may enable it in your " -"configuration or admin settings." +"The API is disabled by default in the application. You may enable it in " +"your configuration or admin settings." msgstr "" -"Standaard is de API in de applicatie uitgeschakeld. Je kunt deze inschakelen " -"in het configuratiescherm of beheerderpaneel." +"Standaard is de API in de applicatie uitgeschakeld. Je kunt deze " +"inschakelen in het configuratiescherm of beheerderpaneel." -#: ../../api.rst:18 ../../api.rst:66 +#: ../../api.rst:18 ../../api.rst:71 msgid "Example" msgstr "Voorbeeld" @@ -62,26 +56,26 @@ msgstr "Autorisatie" #: ../../api.rst:25 msgid "" -"Besides allowing the API to listen for requests, you will also need use the " -"generated API Auth Key. It can be found on the same page as in the " +"Besides allowing the API to listen for requests, you will also need use " +"the generated API Auth Key. It can be found on the same page as in the " "screenshot above. The configuration page will also display it, but only " -"partly. Feel free to alter the API Auth Key when required. The application " -"initially generates one randomly for you." +"partly. Feel free to alter the API Auth Key when required. The " +"application initially generates one randomly for you." msgstr "" -"Naast het inschakelen van de API zul je ook een (automatisch) gegenereerde " -"API autorisatiesleutel moeten gebruiken. Deze kun je terugvinden op dezelfde " -"pagina als in bovenstaand screenshot. Op de configuratiepagina staat de " -"sleutel ook, maar slechts ten delete. Pas overigens gerust de API " -"autorisatiesleutel naar wens aan. De applicatie genereert initieel " -"(eenmalig) een voor je." +"Naast het inschakelen van de API zul je ook een (automatisch) " +"gegenereerde API autorisatiesleutel moeten gebruiken. Deze kun je " +"terugvinden op dezelfde pagina als in bovenstaand screenshot. Op de " +"configuratiepagina staat de sleutel ook, maar slechts ten delete. Pas " +"overigens gerust de API autorisatiesleutel naar wens aan. De applicatie " +"genereert initieel (eenmalig) een voor je." #: ../../api.rst:29 msgid "" "You should pass it in the header of every API call. The header should be " "defined as ``X-AUTHKEY``. See below for an example." msgstr "" -"Je moet deze gebruiken voor elke API call die je uitvoert. De header heet " -"``X-AUTHKEY``. Zie hieronder voor een voorbeeld." +"Je moet deze gebruiken voor elke API call die je uitvoert. De header heet" +" ``X-AUTHKEY``. Zie hieronder voor een voorbeeld." #: ../../api.rst:32 msgid "Examples" @@ -119,74 +113,86 @@ msgstr "" msgid "Parameters" msgstr "Parameters" -#: ../../api.rst:61 +#: ../../api.rst:64 +msgid "" +"Since ``v1.6`` this call now returns ``HTTP 201`` instead of ``HTTP 200``" +" when successful." +msgstr "" +"Sinds ``v1.6`` geeft deze call ``HTTP 201`` terug in plaats van ``HTTP " +"200``, wanneer succesvol." + +#: ../../api.rst:66 msgid "Method: ``POST``" msgstr "Methode: ``POST``" -#: ../../api.rst:62 +#: ../../api.rst:67 msgid "" "Data: ``telegram`` (as raw string containing all linefeeds ``\\n``, and " "carriage returns ``\\r``, as well!)" msgstr "" -"Data: ``telegram`` (als een ruwe tekenreeks inclusief zowel alle regeleindes " -"``\\n`` als 'carriage returns' ``\\r``)" +"Data: ``telegram`` (als een ruwe tekenreeks inclusief zowel alle " +"regeleindes ``\\n`` als 'carriage returns' ``\\r``)" -#: ../../api.rst:63 -msgid "Status code returned: ``HTTP 200`` on success, any other on failure." +#: ../../api.rst:68 +msgid "Status code returned: ``HTTP 201`` on success, any other on failure." msgstr "" -"Status code resultaat: ``HTTP 200`` wanneer succesvol, elke andere code bij " -"falen." +"Status code resultaat: ``HTTP 201`` wanneer succesvol, elke andere code " +"bij falen." -#: ../../api.rst:68 +#: ../../api.rst:73 msgid "(using the ``requests`` library available on PIP)::" msgstr "(met de ``requests`` tool beschikbaar in PIP)::" -#: ../../api.rst:113 +#: ../../api.rst:118 msgid "Script" msgstr "Script" -#: ../../api.rst:114 +#: ../../api.rst:119 msgid "" -"Below is a more detailed script you can use to run via Supervisor. It will " -"send telegrams to one or multiple instances of DSMR-reader." +"Below is a more detailed script you can use to run via Supervisor. It " +"will send telegrams to one or multiple instances of DSMR-reader." msgstr "" -"Hieronder staat een uitgebreider script die je via Supervisor kan draaien. " -"Dit script stuurt telegrammen door naar één of meerdere instanties van DSMR-" -"reader." +"Hieronder staat een uitgebreider script die je via Supervisor kan " +"draaien. Dit script stuurt telegrammen door naar één of meerdere " +"instanties van DSMR-reader." -#: ../../api.rst:119 +#: ../../api.rst:124 msgid "" -"You will still require the ``dsmr`` user and VirtualEnv, :doc:`as discussed " -"in the install guide` in **chapters 3 and 6**!" +"You will still require the ``dsmr`` user and VirtualEnv, :doc:`as " +"discussed in the install guide` in **chapters 3 and 6**!" msgstr "" -"Je hebt nog steeds de ``dsmr`` gebruiker en VirtualEnv nodig, :doc:`zoals " -"besproken in de installatiehandleiding` in **hoofdstukken 3 en " -"6**!" +"Je hebt nog steeds de ``dsmr`` gebruiker en VirtualEnv nodig, :doc:`zoals" +" besproken in de installatiehandleiding` in **hoofdstukken " +"3 en 6**!" -#: ../../api.rst:121 +#: ../../api.rst:126 msgid "**VirtualEnv**::" msgstr "**VirtualEnv**::" -#: ../../api.rst:130 +#: ../../api.rst:135 msgid "The serial connection in this example is based on ``DSMR v4``." msgstr "" -"De seriële verbinding in het voorbeeld hieronder is gebaseerd op ``DSMR v4``." +"De seriële verbinding in het voorbeeld hieronder is gebaseerd op ``DSMR " +"v4``." -#: ../../api.rst:134 +#: ../../api.rst:139 msgid "Don't forget to insert your own configuration below in ``API_SERVERS``." msgstr "" "Vergeet niet om je eigen configuratie hieronder in te stellen in " "``API_SERVERS``." -#: ../../api.rst:136 +#: ../../api.rst:141 msgid "Client file in ``/home/dsmr/dsmr_datalogger_api_client.py``::" msgstr "Client bestand in ``/home/dsmr/dsmr_datalogger_api_client.py``::" -#: ../../api.rst:231 +#: ../../api.rst:243 msgid "Supervisor config in ``/etc/supervisor/conf.d/dsmr-client.conf``::" -msgstr "" -"Supervisor configuratie in ``/etc/supervisor/conf.d/dsmr-client.conf``::" +msgstr "Supervisor configuratie in ``/etc/supervisor/conf.d/dsmr-client.conf``::" -#: ../../api.rst:248 +#: ../../api.rst:260 msgid "**Supervisor**::" msgstr "**Supervisor**::" + +#~ msgid "Contents" +#~ msgstr "Inhoud" + diff --git a/docs/locale/nl/LC_MESSAGES/changelog.mo b/docs/locale/nl/LC_MESSAGES/changelog.mo index 6e92d9d899598b7bca97479226dcdaed15d0b85f..145157ca44563bfe337aa6df71a0cc1c844c34ec 100644 GIT binary patch delta 441 zcmZwDy-Pw-7{~G7HM@GXG$m@WFm8cEh9?WbwYfE$=!%Z<#M25H`Mu};Q591jB)=w~v z*EofDxQJbJFdve}v4lm|mT;eWqfgpHJ1l);9WU^pUmCGgQ_7YqEaW0VqB?FeKgC1r z;SCA5qe0=ZSa6{QoMC?jm+=gT@eN)4!7cuC=k zW#ec_qNd()13z&Wt2`0MM81CqjroJdMNj^#(4_yeq!9NJHN`zdDe*9h(v)8;;kB&W m_Il{vc8YmZ%9=uX-YYm0ky(>9b7kXIoG))D_S#;Hzu3QT(=odM delta 529 zcmX}oODIHP6u|K_gL!#NEIhhGW@DN=BacZIC@D%wc`P(F*LZcWW(FZyQZ{s1+FB82 zc34|?SKf6CtcZ%u)>%RQOPB1`zjnnv!)i_uzQi@a9jB!k`ejg9Xvn3+uoG%Ad zeKOHkCZbvqEaw0U?{SX&qk>oBc%{f9&fo^#BW1#VxtFUN)uF%Ow{V8AJa-W_uR6uU zbHQ;^pjt}<{)5X4jS#vf<+kpqwf7tso&n2D8D=V(>2%(?yn1^utm!?Gkp1InatAxK zP%sj<+q_@?k*FD8jmC|LW-j|C+lLI(NJLXsBBG61Mr4EM*S3tMxd~c=0=Df8U POIj=O=$etq`kr0CjX_I{ diff --git a/docs/locale/nl/LC_MESSAGES/changelog.po b/docs/locale/nl/LC_MESSAGES/changelog.po index 7ac8ba393..3649b4d2a 100644 --- a/docs/locale/nl/LC_MESSAGES/changelog.po +++ b/docs/locale/nl/LC_MESSAGES/changelog.po @@ -8,25 +8,19 @@ msgid "" msgstr "" "Project-Id-Version: DSMR Reader v1.x\n" "Report-Msgid-Bugs-To: Dennis Siemensma \n" -"POT-Creation-Date: 2017-01-03 19:26+0100\n" -"PO-Revision-Date: 2017-01-04 20:37+0100\n" +"POT-Creation-Date: 2017-03-17 10:56+0100\n" +"PO-Revision-Date: 2017-01-21 14:17+0100\n" "Last-Translator: Dennis Siemensma \n" "Language-Team: Dennis Siemensma \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.3.4\n" -"Language: nl\n" -"X-Generator: Poedit 1.8.7.1\n" #: ../../changelog.rst:2 msgid "Changelog" msgstr "Wijzigingenoverzicht" -#: ../../changelog.rst -msgid "Contents" -msgstr "Inhoudsopgave" - #: ../../changelog.rst:11 msgid "Upgrading" msgstr "Updaten" @@ -36,983 +30,1179 @@ msgid "" "Please make sure you have a fresh **database backup** before upgrading! " "Upgrading is very easy due to a builtin mechanism." msgstr "" -"Zorg er alsjeblieft voor dat je altijd een versie **database back-up** hebt, " -"vóórdat je upgrade! Het upgraden zelf is overigens erg eenvoudig via een " -"ingebouwd mechanisme." +"Zorg er alsjeblieft voor dat je altijd een versie **database back-up** " +"hebt, vóórdat je upgrade! Het upgraden zelf is overigens erg eenvoudig " +"via een ingebouwd mechanisme." #: ../../changelog.rst:16 msgid "" -"`About back-ups `_." +"`About back-ups `_." msgstr "" -"`Over back-ups `_." +"`Over back-ups `_." #: ../../changelog.rst:17 msgid "" -"`About upgrading `_." +"`About upgrading `_." msgstr "" -"`Over update `_." +"`Over update `_." #: ../../changelog.rst:22 msgid "v1.6.0 - 2017-xx-xx" msgstr "" -#: ../../changelog.rst:24 ../../changelog.rst:45 ../../changelog.rst:69 -#: ../../changelog.rst:81 ../../changelog.rst:95 ../../changelog.rst:102 -#: ../../changelog.rst:112 ../../changelog.rst:123 ../../changelog.rst:139 -#: ../../changelog.rst:146 ../../changelog.rst:153 ../../changelog.rst:166 -#: ../../changelog.rst:28 ../../changelog.rst:46 ../../changelog.rst:70 -#: ../../changelog.rst:82 ../../changelog.rst:96 ../../changelog.rst:103 -#: ../../changelog.rst:113 ../../changelog.rst:124 ../../changelog.rst:140 -#: ../../changelog.rst:147 ../../changelog.rst:154 ../../changelog.rst:167 +#: ../../changelog.rst:26 +msgid "" +"Support for ``MySQL`` has been **deprecated** since ``DSMR-reader v1.6`` " +"and will be discontinued completely in a later release. Please use a " +"PostgreSQL database instead. Users already running MySQL will be " +"supported in easily migrating to PostgreSQL in the future." +msgstr "" + +#: ../../changelog.rst:31 +msgid "" +"**Change in API:** The telegram creation API now returns an ``HTTP 201`` " +"response when successful. An ``HTTP 200`` was returned in former " +"versions. :doc:`View API docs`." +msgstr "" + +#: ../../changelog.rst:37 ../../changelog.rst:55 ../../changelog.rst:64 +#: ../../changelog.rst:74 ../../changelog.rst:83 ../../changelog.rst:93 +#: ../../changelog.rst:102 ../../changelog.rst:120 ../../changelog.rst:139 +#: ../../changelog.rst:164 ../../changelog.rst:177 ../../changelog.rst:192 +#: ../../changelog.rst:200 ../../changelog.rst:211 ../../changelog.rst:223 +#: ../../changelog.rst:240 ../../changelog.rst:248 ../../changelog.rst:256 +#: ../../changelog.rst:270 msgid "**Tickets resolved in this release:**" msgstr "**Tickets die opgelost zijn in deze release:**" -#: ../../changelog.rst:26 +#: ../../changelog.rst:39 +#, fuzzy msgid "" -"Automatic refresh of dashboard charts (`#210 `_)." +"[`#221 `_] " +"Support for DSMR-firmware v5.0." msgstr "" +"De ondersteuning voor ``Python 3.3`` is **vervallen** wegens de Django " +"upgrade (`#103 `_)." -#: ../../changelog.rst:27 +#: ../../changelog.rst:40 +#, fuzzy +msgid "" +"[`#237 `_] " +"Redesign: Status page." +msgstr "" +"De ondersteuning voor ``Python 3.3`` is **vervallen** wegens de Django " +"upgrade (`#103 `_)." + +#: ../../changelog.rst:41 +#, fuzzy +msgid "" +"[`#249 `_] " +"Req: Add iOS icon for Bookmark." +msgstr "" +"De ondersteuning voor ``Python 3.3`` is **vervallen** wegens de Django " +"upgrade (`#103 `_)." + +#: ../../changelog.rst:42 +#, fuzzy +msgid "" +"[`#232 `_] " +"Docs: Explain settings/options." +msgstr "" +"De ondersteuning voor ``Python 3.3`` is **vervallen** wegens de Django " +"upgrade (`#103 `_)." + +#: ../../changelog.rst:43 msgid "" -"Extend API docs with additional example (`#185 `_)." +"[`#260 `_] Add" +" link to readthedocs in Django for Dropbox instructions." msgstr "" -#: ../../changelog.rst:28 +#: ../../changelog.rst:44 msgid "" -"Docs: How to restore backup (`#190 `_)." +"[`#211 `_] API" +" request should return HTTP 201 instead of HTTP 200." msgstr "" -#: ../../changelog.rst:21 +#: ../../changelog.rst:45 +#, fuzzy +msgid "" +"[`#191 `_] " +"Deprecate MySQL support." +msgstr "" +"De ondersteuning voor ``Python 3.3`` is **vervallen** wegens de Django " +"upgrade (`#103 `_)." + +#: ../../changelog.rst:46 +#, fuzzy +msgid "" +"[`#251 `_] " +"Buienradar Uncaught exception." +msgstr "" +"De ondersteuning voor ``Python 3.3`` is **vervallen** wegens de Django " +"upgrade (`#103 `_)." + +#: ../../changelog.rst:47 +#, fuzzy +msgid "" +"[`#257 `_] " +"Requirements update (February 2017)." +msgstr "" +"De ondersteuning voor ``Python 3.3`` is **vervallen** wegens de Django " +"upgrade (`#103 `_)." + +#: ../../changelog.rst:48 +#, fuzzy +msgid "" +"[`#274 `_] " +"Requirements update (March 2017)." +msgstr "" +"De ondersteuning voor ``Python 3.3`` is **vervallen** wegens de Django " +"upgrade (`#103 `_)." + +#: ../../changelog.rst:53 ../../changelog.rst:72 +msgid "v1.5.5 - 2017-01-19" +msgstr "" + +#: ../../changelog.rst:57 ../../changelog.rst:76 +msgid "" +"Remove readonly restriction for editing statistics in admin interface " +"(`#242 `_)." +msgstr "" + +#: ../../changelog.rst:62 ../../changelog.rst:81 +msgid "v1.5.4 - 2017-01-12" +msgstr "" + +#: ../../changelog.rst:66 ../../changelog.rst:85 +msgid "" +"Improve datalogger for DSMR v5.0 (`#212 " +"`_)." +msgstr "" + +#: ../../changelog.rst:67 ../../changelog.rst:86 +msgid "" +"Fixed another bug in MinderGas API client implementation (`#228 " +"`_)." +msgstr "" + +#: ../../changelog.rst:91 +msgid "v1.5.3 - 2017-01-11" +msgstr "" + +#: ../../changelog.rst:95 +msgid "" +"Improve MinderGas API client implementation (`#228 " +"`_)." +msgstr "" + +#: ../../changelog.rst:100 +msgid "v1.5.2 - 2017-01-09" +msgstr "" + +#: ../../changelog.rst:104 +msgid "" +"Automatic refresh of dashboard charts (`#210 " +"`_)." +msgstr "" + +#: ../../changelog.rst:105 +msgid "" +"Mindergas.nl API: Tijdstip van verzending willekeurig maken (`#204 " +"`_)." +msgstr "" + +#: ../../changelog.rst:106 +msgid "" +"Extend API docs with additional example (`#185 " +"`_)." +msgstr "" + +#: ../../changelog.rst:107 +msgid "" +"Docs: How to restore backup (`#190 `_)." +msgstr "" + +#: ../../changelog.rst:108 +msgid "" +"Log errors occured to file (`#181 `_)." +msgstr "" + +#: ../../changelog.rst:113 msgid "v1.5.1 - 2017-01-04" msgstr "" -#: ../../changelog.rst:25 +#: ../../changelog.rst:117 msgid "" -"This patch contains no new features and **only solves upgrading issues** for " -"some users." +"This patch contains no new features and **only solves upgrading issues** " +"for some users." msgstr "" "Deze patch bevat geen nieuwe features en **lost alleen upgrade-problemen " "op** voor sommige gebruikers." -#: ../../changelog.rst:30 +#: ../../changelog.rst:122 msgid "" -"Fix for issues `#200 `_ & `#217 `_, which is caused by omitting the switch to the VirtualEnv. " -"This was not documented well enough in early versions of this project, " -"causing failed upgrades." +"Fix for issues `#200 `_ & `#217 `_, which is caused by omitting the switch to the " +"VirtualEnv. This was not documented well enough in early versions of this" +" project, causing failed upgrades." msgstr "" -"Oplossing voor tickets `#200 `_ & `#217 `_, welke veroorzaakt worden door het niet wisselen naar de " -"VirtualEnv voor de upgrade. In eerdere versies van de project-documentatie " -"stond dit niet duidelijk genoeg beschreven en dat veroorzaakt deze problemen." +"Oplossing voor tickets `#200 `_ & `#217 `_, welke veroorzaakt worden door het niet wisselen " +"naar de VirtualEnv voor de upgrade. In eerdere versies van de project-" +"documentatie stond dit niet duidelijk genoeg beschreven en dat " +"veroorzaakt deze problemen." -#: ../../changelog.rst:33 +#: ../../changelog.rst:127 msgid "v1.5.0 - 2017-01-01" msgstr "" -#: ../../changelog.rst:35 ../../changelog.rst:77 +#: ../../changelog.rst:129 ../../changelog.rst:173 msgid "**Change in Python support**" msgstr "**Wijziging in Python-ondersteuning**" -#: ../../changelog.rst:37 +#: ../../changelog.rst:131 msgid "" "The support for ``Python 3.3`` has been **dropped** due to the Django " -"upgrade (`#103 `_)." +"upgrade (`#103 `_)." msgstr "" "De ondersteuning voor ``Python 3.3`` is **vervallen** wegens de Django " -"upgrade (`#103 `_)." +"upgrade (`#103 `_)." -#: ../../changelog.rst:38 +#: ../../changelog.rst:132 msgid "" "There is **experimental support** for ``Python 3.6`` and ``Python 3.7 " -"(nightly)`` as the unittests are `now built against those versions `_ as well (`#167 " +"(nightly)`` as the unittests are `now built against those versions `_ as well (`#167 " "`_)." msgstr "" -"Er is **experimentele ondersteuning** voor ``Python 3.6`` en ``Python 3.7 " -"(nightly)`` gezien de unittests `momenteel ook in voor die versies worden " -"uitgevoerd. `_ " -"(`#167 `_)." +"Er is **experimentele ondersteuning** voor ``Python 3.6`` en ``Python 3.7" +" (nightly)`` gezien de unittests `momenteel ook in voor die versies " +"worden uitgevoerd. `_ (`#167 `_)." -#: ../../changelog.rst:40 +#: ../../changelog.rst:134 msgid "**Legacy warning**" msgstr "**Waarschuwing voor legacy**" -#: ../../changelog.rst:42 +#: ../../changelog.rst:136 msgid "" -"The migrations that were squashed together in (`#31 `_) have been **removed**. This will " -"only affect you when you are currently still running a dsmrreader-version of " -"**before** ``v0.13 (β)``." +"The migrations that were squashed together in (`#31 " +"`_) have been " +"**removed**. This will only affect you when you are currently still " +"running a dsmrreader-version of **before** ``v0.13 (β)``." msgstr "" -"De migraties die samengevoegd zijn in (`#31 `_) zijn **verwijderd**. Hier heb je " -"alleen maar te maken wanneer je nog gebruik maakt van een dsmrreader-versie " -"**vóór** ``v0.13 (β)``." +"De migraties die samengevoegd zijn in (`#31 " +"`_) zijn " +"**verwijderd**. Hier heb je alleen maar te maken wanneer je nog gebruik " +"maakt van een dsmrreader-versie **vóór** ``v0.13 (β)``." -#: ../../changelog.rst:43 +#: ../../changelog.rst:137 msgid "" -"If you are indeed still running ``< v0.13 (β)``, please upgrade to ``v1.4`` " -"first (!), followed by an upgrade to ``v1.5``." +"If you are indeed still running ``< v0.13 (β)``, please upgrade to " +"``v1.4`` first (!), followed by an upgrade to ``v1.5``." msgstr "" -"Wanneer je nog steeds een versie van vóór ``< v0.13 (β)`` draait, upgrade " -"dan eerst naar ``v1.4`` (!), gevolgd door een upgrade naar ``v1.5``." +"Wanneer je nog steeds een versie van vóór ``< v0.13 (β)`` draait, upgrade" +" dan eerst naar ``v1.4`` (!), gevolgd door een upgrade naar ``v1.5``." -#: ../../changelog.rst:47 +#: ../../changelog.rst:141 msgid "" -"Verify telegrams' CRC (`#188 `_)." +"Verify telegrams' CRC (`#188 `_)." msgstr "" -#: ../../changelog.rst:48 +#: ../../changelog.rst:142 msgid "" -"Display last 24 hours on dashboard (`#164 `_)." +"Display last 24 hours on dashboard (`#164 " +"`_)." msgstr "" -#: ../../changelog.rst:49 +#: ../../changelog.rst:143 msgid "" -"Status page visualisation (`#172 `_)." +"Status page visualisation (`#172 `_)." msgstr "" -#: ../../changelog.rst:50 +#: ../../changelog.rst:144 msgid "" -"Store and display phases consumption (`#161 `_)." +"Store and display phases consumption (`#161 " +"`_)." msgstr "" -#: ../../changelog.rst:51 +#: ../../changelog.rst:145 msgid "" -"Weather graph not showing when no gas data is available (`#170 `_)." +"Weather graph not showing when no gas data is available (`#170 " +"`_)." msgstr "" -#: ../../changelog.rst:52 +#: ../../changelog.rst:146 msgid "" "Upgrade to ChartJs 2.0 (`#127 `_)." msgstr "" -#: ../../changelog.rst:53 +#: ../../changelog.rst:147 msgid "" -"Improve Statistics page performance (`#173 `_)." +"Improve Statistics page performance (`#173 " +"`_)." msgstr "" -#: ../../changelog.rst:54 +#: ../../changelog.rst:148 msgid "" -"Version checker at github (`#166 `_)." +"Version checker at github (`#166 `_)." msgstr "" -#: ../../changelog.rst:55 +#: ../../changelog.rst:149 msgid "" -"Remove required login for dismissal of in-app notifications (`#179 `_)." +"Remove required login for dismissal of in-app notifications (`#179 " +"`_)." msgstr "" -#: ../../changelog.rst:56 +#: ../../changelog.rst:150 msgid "" -"Round numbers displayed in GUI to 2 decimals (`#183 `_)." +"Round numbers displayed in GUI to 2 decimals (`#183 " +"`_)." msgstr "" -#: ../../changelog.rst:57 +#: ../../changelog.rst:151 msgid "" -"Switch Nosetests to Pytest (+ pytest-cov) (`#167 `_)." +"Switch Nosetests to Pytest (+ pytest-cov) (`#167 " +"`_)." msgstr "" -#: ../../changelog.rst:58 +#: ../../changelog.rst:152 msgid "" -"PyLama code audit (+ pytest-cov) (`#158 `_)." +"PyLama code audit (+ pytest-cov) (`#158 " +"`_)." msgstr "" -#: ../../changelog.rst:59 +#: ../../changelog.rst:153 msgid "" "Double upgrade of Django framework ``Django 1.8`` -> ``Django 1.9`` -> " -"``Django 1.10`` (`#103 `_)." +"``Django 1.10`` (`#103 `_)." msgstr "" -#: ../../changelog.rst:60 +#: ../../changelog.rst:154 msgid "" -"Force ``PYTHONUNBUFFERED`` for supervisor commands (`#176 `_)." +"Force ``PYTHONUNBUFFERED`` for supervisor commands (`#176 " +"`_)." msgstr "" -#: ../../changelog.rst:61 +#: ../../changelog.rst:155 msgid "" -"Documentation updates for v1.5 (`#171 `_)." +"Documentation updates for v1.5 (`#171 `_)." msgstr "" -#: ../../changelog.rst:62 +#: ../../changelog.rst:156 msgid "" -"Requirements update for v1.5 (december 2016) (`#182 `_)." +"Requirements update for v1.5 (december 2016) (`#182 " +"`_)." msgstr "" -#: ../../changelog.rst:63 +#: ../../changelog.rst:157 msgid "" -"Improved backend process logging (`#184 `_)." +"Improved backend process logging (`#184 " +"`_)." msgstr "" -#: ../../changelog.rst:67 +#: ../../changelog.rst:162 msgid "v1.4.1 - 2016-12-12" msgstr "" -#: ../../changelog.rst:71 +#: ../../changelog.rst:166 msgid "" -"Consumption chart hangs due to unique_key violation (`#174 `_)." +"Consumption chart hangs due to unique_key violation (`#174 " +"`_)." msgstr "" -#: ../../changelog.rst:72 +#: ../../changelog.rst:167 msgid "" -"NoReverseMatch at / Reverse for 'docs' (`#175 `_)." +"NoReverseMatch at / Reverse for 'docs' (`#175 " +"`_)." msgstr "" -#: ../../changelog.rst:76 +#: ../../changelog.rst:172 msgid "v1.4.0 - 2016-11-28" msgstr "" -#: ../../changelog.rst:79 +#: ../../changelog.rst:175 msgid "" -"Support for ``Python 3.5`` has been added officially (`#55 `_)." +"Support for ``Python 3.5`` has been added officially (`#55 " +"`_)." msgstr "" -#: ../../changelog.rst:83 +#: ../../changelog.rst:179 msgid "" -"Push notifications for Notify My Android / Prowl (iOS), written by Jeroen " -"Peters (`#152 `_)." +"Push notifications for Notify My Android / Prowl (iOS), written by Jeroen" +" Peters (`#152 `_)." msgstr "" -#: ../../changelog.rst:84 +#: ../../changelog.rst:180 msgid "" -"Support for both single and high/low tariff (`#130 `_)." +"Support for both single and high/low tariff (`#130 " +"`_)." msgstr "" -#: ../../changelog.rst:85 +#: ../../changelog.rst:181 msgid "" -"Add new note from Dashboard has wrong time format (`#159 `_)." +"Add new note from Dashboard has wrong time format (`#159 " +"`_)." msgstr "" -#: ../../changelog.rst:86 +#: ../../changelog.rst:182 msgid "" -"Display estimated price for current usage in Dashboard (`#155 `_)." +"Display estimated price for current usage in Dashboard (`#155 " +"`_)." msgstr "" -#: ../../changelog.rst:87 +#: ../../changelog.rst:183 msgid "" -"Dropbox API v1 deprecated in June 2017 (`#142 `_)." +"Dropbox API v1 deprecated in June 2017 (`#142 " +"`_)." msgstr "" -#: ../../changelog.rst:88 +#: ../../changelog.rst:184 msgid "" -"Improve code coverage (`#151 `_)." +"Improve code coverage (`#151 `_)." msgstr "" -#: ../../changelog.rst:89 +#: ../../changelog.rst:185 msgid "" -"Restyle configuration overview (`#156 `_)." +"Restyle configuration overview (`#156 `_)." msgstr "" -#: ../../changelog.rst:90 +#: ../../changelog.rst:186 msgid "" -"Capability based push notifications (`#165 `_)." +"Capability based push notifications (`#165 " +"`_)." msgstr "" -#: ../../changelog.rst:94 +#: ../../changelog.rst:191 msgid "v1.3.2 - 2016-11-08" msgstr "" -#: ../../changelog.rst:97 +#: ../../changelog.rst:194 msgid "" -"Requirements update (november 2016) (`#150 `_)." +"Requirements update (november 2016) (`#150 " +"`_)." msgstr "" -#: ../../changelog.rst:101 +#: ../../changelog.rst:199 msgid "v1.3.1 - 2016-08-16" msgstr "" -#: ../../changelog.rst:104 +#: ../../changelog.rst:202 msgid "" "CSS large margin-bottom (`#144 `_)." msgstr "" -#: ../../changelog.rst:105 +#: ../../changelog.rst:203 msgid "" -"Django security releases issued: 1.8.14 (`#147 `_)." +"Django security releases issued: 1.8.14 (`#147 " +"`_)." msgstr "" -#: ../../changelog.rst:106 +#: ../../changelog.rst:204 msgid "" -"Requirements update (August 2016) (`#148 `_)." +"Requirements update (August 2016) (`#148 " +"`_)." msgstr "" -#: ../../changelog.rst:107 +#: ../../changelog.rst:205 msgid "" -"Query performance improvements (`#149 `_)." +"Query performance improvements (`#149 `_)." msgstr "" -#: ../../changelog.rst:111 +#: ../../changelog.rst:210 msgid "v1.3.0 - 2016-07-15" msgstr "" -#: ../../changelog.rst:114 +#: ../../changelog.rst:213 msgid "" -"API endpoint for datalogger (`#140 `_)." +"API endpoint for datalogger (`#140 `_)." msgstr "" -#: ../../changelog.rst:115 +#: ../../changelog.rst:214 msgid "" -"Colors for charts (`#137 `_)." +"Colors for charts (`#137 `_)." msgstr "" -#: ../../changelog.rst:116 +#: ../../changelog.rst:215 msgid "" "Data export: Mindergas.nl (`#10 `_)." msgstr "" -#: ../../changelog.rst:117 +#: ../../changelog.rst:216 msgid "" -"Requirement upgrade (`#143 `_)." +"Requirement upgrade (`#143 `_)." msgstr "" -#: ../../changelog.rst:118 +#: ../../changelog.rst:217 msgid "" -"Installation wizard for first time use (`#139 `_)." +"Installation wizard for first time use (`#139 " +"`_)." msgstr "" -#: ../../changelog.rst:122 +#: ../../changelog.rst:222 msgid "v1.2.0 - 2016-05-18" msgstr "" -#: ../../changelog.rst:125 +#: ../../changelog.rst:225 msgid "" -"Energy supplier prices does not indicate tariff type (Django admin) (`#126 " -"`_)." +"Energy supplier prices does not indicate tariff type (Django admin) " +"(`#126 `_)." msgstr "" -#: ../../changelog.rst:126 +#: ../../changelog.rst:226 msgid "" -"Requirements update (`#128 `_)." +"Requirements update (`#128 `_)." msgstr "" -#: ../../changelog.rst:127 +#: ../../changelog.rst:227 msgid "" -"Force backup (`#123 `_)." +"Force backup (`#123 `_)." msgstr "" -#: ../../changelog.rst:128 +#: ../../changelog.rst:228 msgid "" "Update clean-install.md (`#131 `_)." msgstr "" -#: ../../changelog.rst:129 +#: ../../changelog.rst:229 msgid "" -"Improve data export field names (`#132 `_)." +"Improve data export field names (`#132 " +"`_)." msgstr "" -#: ../../changelog.rst:130 +#: ../../changelog.rst:230 msgid "" -"Display average temperature in archive (`#122 `_)." +"Display average temperature in archive (`#122 " +"`_)." msgstr "" -#: ../../changelog.rst:131 +#: ../../changelog.rst:231 msgid "" -"Pie charts on trends page overlap their canvas (`#136 `_)." +"Pie charts on trends page overlap their canvas (`#136 " +"`_)." msgstr "" -#: ../../changelog.rst:132 +#: ../../changelog.rst:232 msgid "" -"'Slumber' consumption (`#115 `_)." +"'Slumber' consumption (`#115 `_)." msgstr "" -#: ../../changelog.rst:133 +#: ../../changelog.rst:233 msgid "" -"Show lowest & highest Watt peaks (`#138 `_)." +"Show lowest & highest Watt peaks (`#138 " +"`_)." msgstr "" -#: ../../changelog.rst:134 +#: ../../changelog.rst:234 msgid "" "Allow day & hour statistics reset due to changing energy prices (`#95 " "`_)." msgstr "" -#: ../../changelog.rst:138 +#: ../../changelog.rst:239 msgid "v1.1.2 - 2016-05-01" msgstr "" -#: ../../changelog.rst:141 +#: ../../changelog.rst:242 msgid "" -"Trends page giving errors (when lacking data) (`#125 `_)." +"Trends page giving errors (when lacking data) (`#125 " +"`_)." msgstr "" -#: ../../changelog.rst:145 +#: ../../changelog.rst:247 msgid "v1.1.1 - 2016-04-27" msgstr "" -#: ../../changelog.rst:148 +#: ../../changelog.rst:250 msgid "" -"Improve readme (`#124 `_)." +"Improve readme (`#124 `_)." msgstr "" -#: ../../changelog.rst:152 +#: ../../changelog.rst:255 msgid "v1.1.0 - 2016-04-23" msgstr "" -#: ../../changelog.rst:155 +#: ../../changelog.rst:258 msgid "" -"Autorefresh dashboard (`#117 `_)." +"Autorefresh dashboard (`#117 `_)." msgstr "" -#: ../../changelog.rst:156 +#: ../../changelog.rst:259 msgid "" -"Improve line graphs' visibility (`#111 `_)." +"Improve line graphs' visibility (`#111 " +"`_)." msgstr "" -#: ../../changelog.rst:157 +#: ../../changelog.rst:260 msgid "" -"Easily add notes (`#110 `_)." +"Easily add notes (`#110 `_)." msgstr "" -#: ../../changelog.rst:158 +#: ../../changelog.rst:261 msgid "" -"Export data points in CSV format (`#2 `_)." +"Export data points in CSV format (`#2 `_)." msgstr "" -#: ../../changelog.rst:159 +#: ../../changelog.rst:262 msgid "" -"Allow day/month/year comparison (`#94 `_)." +"Allow day/month/year comparison (`#94 `_)." msgstr "" -#: ../../changelog.rst:160 +#: ../../changelog.rst:263 msgid "" -"Docs: Add FAQ and generic application info (`#113 `_)." +"Docs: Add FAQ and generic application info (`#113 " +"`_)." msgstr "" -#: ../../changelog.rst:161 +#: ../../changelog.rst:264 msgid "" -"Support for Iskra meter (DSMR 2.x) (`#120 `_)." +"Support for Iskra meter (DSMR 2.x) (`#120 " +"`_)." msgstr "" -#: ../../changelog.rst:165 +#: ../../changelog.rst:269 msgid "v1.0.1 - 2016-04-07" msgstr "" -#: ../../changelog.rst:168 +#: ../../changelog.rst:272 msgid "" -"Update licence to OSI compatible one (`#119 `_)." +"Update licence to OSI compatible one (`#119 " +"`_)." msgstr "" -#: ../../changelog.rst:172 +#: ../../changelog.rst:277 msgid "v1.0.0 - 2016-04-07" msgstr "" -#: ../../changelog.rst:173 +#: ../../changelog.rst:278 msgid "First official stable release." msgstr "Eerste officiële stabiele release." -#: ../../changelog.rst:177 +#: ../../changelog.rst:283 msgid "[β] v0.1 (2015-10-29) to 0.16 (2016-04-06)" msgstr "" -#: ../../changelog.rst:180 +#: ../../changelog.rst:286 msgid "" -"All previous beta releases/changes have been combined to a single list below." +"All previous beta releases/changes have been combined to a single list " +"below." msgstr "" "Alle vorige bèta releases/veranderingen zijn gecombineerd tot een enkele " "lijst hieronder." -#: ../../changelog.rst:182 +#: ../../changelog.rst:288 msgid "" -"Move documentation to wiki or RTD (`#90 `_)." +"Move documentation to wiki or RTD (`#90 " +"`_)." msgstr "" -#: ../../changelog.rst:183 +#: ../../changelog.rst:289 msgid "" "Translate README to Dutch (`#16 `_)." msgstr "" -#: ../../changelog.rst:184 +#: ../../changelog.rst:290 msgid "" -"Delete (recent) history page (`#112 `_)." +"Delete (recent) history page (`#112 `_)." msgstr "" -#: ../../changelog.rst:185 +#: ../../changelog.rst:291 msgid "" -"Display most recent temperature in dashboard (`#114 `_)." +"Display most recent temperature in dashboard (`#114 " +"`_)." msgstr "" -#: ../../changelog.rst:186 +#: ../../changelog.rst:292 msgid "" "Upgrade Django to 1.8.12 (`#118 `_)." msgstr "" -#: ../../changelog.rst:188 +#: ../../changelog.rst:294 msgid "" -"Redesign trends page (`#97 `_)." +"Redesign trends page (`#97 `_)." msgstr "" -#: ../../changelog.rst:189 +#: ../../changelog.rst:295 msgid "" "Support for summer time (`#105 `_)." msgstr "" -#: ../../changelog.rst:190 +#: ../../changelog.rst:296 msgid "" -"Support for Daylight Saving Time (DST) transition (`#104 `_)." +"Support for Daylight Saving Time (DST) transition (`#104 " +"`_)." msgstr "" -#: ../../changelog.rst:191 +#: ../../changelog.rst:297 msgid "" -"Add (error) hints to status page (`#106 `_)." +"Add (error) hints to status page (`#106 " +"`_)." msgstr "" -#: ../../changelog.rst:192 +#: ../../changelog.rst:298 msgid "" -"Keep track of version (`#108 `_)." +"Keep track of version (`#108 `_)." msgstr "" -#: ../../changelog.rst:194 +#: ../../changelog.rst:300 msgid "" -"Django 1.8.11 released (`#82 `_)." +"Django 1.8.11 released (`#82 `_)." msgstr "" -#: ../../changelog.rst:195 +#: ../../changelog.rst:301 msgid "" -"Prevent tests from failing due to moment of execution (`#88 `_)." +"Prevent tests from failing due to moment of execution (`#88 " +"`_)." msgstr "" -#: ../../changelog.rst:196 +#: ../../changelog.rst:302 msgid "" -"Statistics page meter positions are broken (`#93 `_)." +"Statistics page meter positions are broken (`#93 " +"`_)." msgstr "" -#: ../../changelog.rst:197 +#: ../../changelog.rst:303 msgid "" -"Archive only shows graph untill 23:00 (11 pm) (`#77 `_)." +"Archive only shows graph untill 23:00 (11 pm) (`#77 " +"`_)." msgstr "" -#: ../../changelog.rst:198 +#: ../../changelog.rst:304 msgid "" -"Trends page crashes due to nullable fields average (`#100 `_)." +"Trends page crashes due to nullable fields average (`#100 " +"`_)." msgstr "" -#: ../../changelog.rst:199 +#: ../../changelog.rst:305 msgid "" -"Trends: Plot peak and off-peak relative to each other (`#99 `_)." +"Trends: Plot peak and off-peak relative to each other (`#99 " +"`_)." msgstr "" -#: ../../changelog.rst:200 +#: ../../changelog.rst:306 msgid "" -"Monitor requirements with requires.io (`#101 `_)." +"Monitor requirements with requires.io (`#101 " +"`_)." msgstr "" -#: ../../changelog.rst:201 +#: ../../changelog.rst:307 msgid "" -"Terminology (`#41 `_)." +"Terminology (`#41 `_)." msgstr "" -#: ../../changelog.rst:202 +#: ../../changelog.rst:308 msgid "" -"Obsolete signals in dsmr_consumption (`#63 `_)." +"Obsolete signals in dsmr_consumption (`#63 " +"`_)." msgstr "" -#: ../../changelog.rst:203 +#: ../../changelog.rst:309 msgid "" -"Individual app testing coverage (`#64 `_)." +"Individual app testing coverage (`#64 `_)." msgstr "" -#: ../../changelog.rst:204 +#: ../../changelog.rst:310 msgid "" -"Support for extra devices on other M-bus (0-n:24.1) (`#92 `_)." +"Support for extra devices on other M-bus (0-n:24.1) (`#92 " +"`_)." msgstr "" -#: ../../changelog.rst:205 +#: ../../changelog.rst:311 msgid "" -"Separate post-deployment commands (`#102 `_)." +"Separate post-deployment commands (`#102 " +"`_)." msgstr "" -#: ../../changelog.rst:207 +#: ../../changelog.rst:313 msgid "" -"Show exceptions in production (webinterface) (`#87 `_)." +"Show exceptions in production (webinterface) (`#87 " +"`_)." msgstr "" -#: ../../changelog.rst:208 +#: ../../changelog.rst:314 msgid "" -"Keep Supervisor processes running (`#79 `_)." +"Keep Supervisor processes running (`#79 " +"`_)." msgstr "" -#: ../../changelog.rst:209 +#: ../../changelog.rst:315 msgid "" -"Hourly stats of 22:00:00+00 every day lack gas (`#78 `_)." +"Hourly stats of 22:00:00+00 every day lack gas (`#78 " +"`_)." msgstr "" -#: ../../changelog.rst:210 +#: ../../changelog.rst:316 msgid "" -"Test Travis-CI with MySQL + MariaDB + PostgreSQL (`#54 `_)." +"Test Travis-CI with MySQL + MariaDB + PostgreSQL (`#54 " +"`_)." msgstr "" -#: ../../changelog.rst:211 +#: ../../changelog.rst:317 msgid "" -"PostgreSQL tests + nosetests + coverage failure: unrecognized configuration " -"parameter \"foreign_key_checks\" (`#62 `_)." +"PostgreSQL tests + nosetests + coverage failure: unrecognized " +"configuration parameter \"foreign_key_checks\" (`#62 " +"`_)." msgstr "" -#: ../../changelog.rst:212 +#: ../../changelog.rst:318 msgid "" -"Performance check (`#83 `_)." +"Performance check (`#83 `_)." msgstr "" -#: ../../changelog.rst:213 +#: ../../changelog.rst:319 msgid "" -"Allow month & year archive (`#66 `_)." +"Allow month & year archive (`#66 `_)." msgstr "" -#: ../../changelog.rst:214 +#: ../../changelog.rst:320 msgid "" -"Graphs keep increasing height on tablet (`#89 `_)." +"Graphs keep increasing height on tablet (`#89 " +"`_)." msgstr "" -#: ../../changelog.rst:216 +#: ../../changelog.rst:322 msgid "" -"Delete StatsSettings(.track) settings model (`#71 `_)." +"Delete StatsSettings(.track) settings model (`#71 " +"`_)." msgstr "" -#: ../../changelog.rst:217 +#: ../../changelog.rst:323 msgid "" "Drop deprecated commands (`#22 `_)." msgstr "" -#: ../../changelog.rst:218 +#: ../../changelog.rst:324 msgid "" -"Datalogger doesn't work properly with DSMR 4.2 (KAIFA-METER) (`#73 `_)." +"Datalogger doesn't work properly with DSMR 4.2 (KAIFA-METER) (`#73 " +"`_)." msgstr "" -#: ../../changelog.rst:219 +#: ../../changelog.rst:325 msgid "" -"Dashboard month statistics costs does not add up (`#75 `_)." +"Dashboard month statistics costs does not add up (`#75 " +"`_)." msgstr "" -#: ../../changelog.rst:220 +#: ../../changelog.rst:326 msgid "" -"Log unhandled exceptions and errors (`#65 `_)." +"Log unhandled exceptions and errors (`#65 " +"`_)." msgstr "" -#: ../../changelog.rst:221 +#: ../../changelog.rst:327 msgid "" "Datalogger crashes with IntegrityError because 'timestamp' is null (`#74 " "`_)." msgstr "" -#: ../../changelog.rst:222 +#: ../../changelog.rst:328 msgid "" -"Trends are always shown in UTC (`#76 `_)." +"Trends are always shown in UTC (`#76 `_)." msgstr "" -#: ../../changelog.rst:223 +#: ../../changelog.rst:329 msgid "" -"Squash migrations (`#31 `_)." +"Squash migrations (`#31 `_)." msgstr "" -#: ../../changelog.rst:224 +#: ../../changelog.rst:330 msgid "" -"Display 'electricity returned' graph in dashboard (`#81 `_)." +"Display 'electricity returned' graph in dashboard (`#81 " +"`_)." msgstr "" -#: ../../changelog.rst:225 +#: ../../changelog.rst:331 msgid "" -"Optional gas (and electricity returned) capabilities tracking (`#70 `_)." +"Optional gas (and electricity returned) capabilities tracking (`#70 " +"`_)." msgstr "" -#: ../../changelog.rst:226 +#: ../../changelog.rst:332 msgid "" -"Add 'electricity returned' to trends page (`#84 `_)." +"Add 'electricity returned' to trends page (`#84 " +"`_)." msgstr "" -#: ../../changelog.rst:228 +#: ../../changelog.rst:334 msgid "" -"Archive: View past days details (`#61 `_)." +"Archive: View past days details (`#61 `_)." msgstr "" -#: ../../changelog.rst:229 +#: ../../changelog.rst:335 msgid "" -"Dashboard: Consumption total for current month (`#60 `_)." +"Dashboard: Consumption total for current month (`#60 " +"`_)." msgstr "" -#: ../../changelog.rst:230 +#: ../../changelog.rst:336 msgid "" -"Check whether gas readings are optional (`#34 `_)." +"Check whether gas readings are optional (`#34 " +"`_)." msgstr "" -#: ../../changelog.rst:231 +#: ../../changelog.rst:337 msgid "" -"Django security releases issued: 1.8.10 (`#68 `_)." +"Django security releases issued: 1.8.10 (`#68 " +"`_)." msgstr "" -#: ../../changelog.rst:232 +#: ../../changelog.rst:338 msgid "" "Notes display in archive (`#69 `_)." msgstr "" -#: ../../changelog.rst:234 +#: ../../changelog.rst:340 msgid "" -"Status page/alerts when features are disabled/unavailable (`#45 `_)." +"Status page/alerts when features are disabled/unavailable (`#45 " +"`_)." msgstr "" -#: ../../changelog.rst:235 +#: ../../changelog.rst:341 msgid "" -"Integrate Travis CI (`#48 `_)." +"Integrate Travis CI (`#48 `_)." msgstr "" -#: ../../changelog.rst:236 +#: ../../changelog.rst:342 msgid "" -"Testing coverage (`#38 `_)." +"Testing coverage (`#38 `_)." msgstr "" -#: ../../changelog.rst:237 +#: ../../changelog.rst:343 msgid "" -"Implement automatic backups & Dropbox cloud storage (`#44 `_)." +"Implement automatic backups & Dropbox cloud storage (`#44 " +"`_)." msgstr "" -#: ../../changelog.rst:238 +#: ../../changelog.rst:344 msgid "" -"Link code coverage service to repository (`#56 `_)." +"Link code coverage service to repository (`#56 " +"`_)." msgstr "" -#: ../../changelog.rst:239 +#: ../../changelog.rst:345 msgid "" -"Explore timezone.localtime() as replacement for datetime.astimezone() (`#50 " -"`_)." +"Explore timezone.localtime() as replacement for datetime.astimezone() " +"(`#50 `_)." msgstr "" -#: ../../changelog.rst:240 +#: ../../changelog.rst:346 msgid "" -"Align GasConsumption.read_at to represent the start of hour (`#40 `_)." +"Align GasConsumption.read_at to represent the start of hour (`#40 " +"`_)." msgstr "" -#: ../../changelog.rst:242 +#: ../../changelog.rst:348 msgid "" -"Cleanup unused static files (`#47 `_)." +"Cleanup unused static files (`#47 `_)." msgstr "" -#: ../../changelog.rst:243 +#: ../../changelog.rst:349 msgid "" -"Investigated mysql_tzinfo_to_sql — Load the Time Zone Tables (`#35 `_)." +"Investigated mysql_tzinfo_to_sql — Load the Time Zone Tables (`#35 " +"`_)." msgstr "" -#: ../../changelog.rst:244 +#: ../../changelog.rst:350 msgid "" -"Make additional DSMR data optional (`#46 `_)." +"Make additional DSMR data optional (`#46 " +"`_)." msgstr "" -#: ../../changelog.rst:245 +#: ../../changelog.rst:351 msgid "" -"Localize graph x-axis (`#42 `_)." +"Localize graph x-axis (`#42 `_)." msgstr "" -#: ../../changelog.rst:246 +#: ../../changelog.rst:352 msgid "" -"Added graph formatting string to gettext file (`#42 `_)." +"Added graph formatting string to gettext file (`#42 " +"`_)." msgstr "" -#: ../../changelog.rst:247 +#: ../../changelog.rst:353 msgid "" -"Different colors for peak & off-peak electricity (`#52 `_)." +"Different colors for peak & off-peak electricity (`#52 " +"`_)." msgstr "" -#: ../../changelog.rst:248 +#: ../../changelog.rst:354 msgid "" -"Admin: Note widget (`#51 `_)." +"Admin: Note widget (`#51 `_)." msgstr "" -#: ../../changelog.rst:249 +#: ../../changelog.rst:355 msgid "" -"Allow GUI to run without data (`#26 `_)." +"Allow GUI to run without data (`#26 `_)." msgstr "" -#: ../../changelog.rst:251 +#: ../../changelog.rst:357 msgid "" "Moved project to GitHub (`#28 `_)." msgstr "" -#: ../../changelog.rst:252 +#: ../../changelog.rst:358 msgid "Added stdout to dsmr_backend to reflect progress." msgstr "" -#: ../../changelog.rst:253 +#: ../../changelog.rst:359 msgid "" "Restore note usage in GUI (`#39 `_)." msgstr "" -#: ../../changelog.rst:255 +#: ../../changelog.rst:361 msgid "" -"Store daily, weekly, monthly and yearly statistics (`#3 `_)." +"Store daily, weekly, monthly and yearly statistics (`#3 " +"`_)." msgstr "" -#: ../../changelog.rst:256 +#: ../../changelog.rst:362 msgid "" -"Improved Recent History page performance a bit. (as result of `#3 `_)" +"Improved Recent History page performance a bit. (as result of `#3 " +"`_)" msgstr "" -#: ../../changelog.rst:257 +#: ../../changelog.rst:363 msgid "" "Updates ChartJS library tot 1.1, disposing django-chartjs plugin. Labels " "finally work! (as result of `#3 `_)" msgstr "" -#: ../../changelog.rst:258 +#: ../../changelog.rst:364 msgid "" -"Added trends page. (as result of `#3 `_)" +"Added trends page. (as result of `#3 `_)" msgstr "" -#: ../../changelog.rst:260 +#: ../../changelog.rst:366 msgid "" -"Recent history setting: set range (`#29 `_)." +"Recent history setting: set range (`#29 " +"`_)." msgstr "" -#: ../../changelog.rst:261 +#: ../../changelog.rst:367 msgid "" -"Mock required for test: dsmr_weather.test_weather_tracking (`#32 `_)." +"Mock required for test: dsmr_weather.test_weather_tracking (`#32 " +"`_)." msgstr "" -#: ../../changelog.rst:263 +#: ../../changelog.rst:369 msgid "" -"Massive refactoring: Separating apps & using signals (`#19 `_)." +"Massive refactoring: Separating apps & using signals (`#19 " +"`_)." msgstr "" -#: ../../changelog.rst:264 +#: ../../changelog.rst:370 msgid "" -"README update: Exit character for cu (`#27 `_, by Jeroen Peters)." +"README update: Exit character for cu (`#27 " +"`_, by Jeroen " +"Peters)." msgstr "" -#: ../../changelog.rst:265 +#: ../../changelog.rst:371 msgid "Fixed untranslated strings in admin interface." msgstr "" -#: ../../changelog.rst:266 +#: ../../changelog.rst:372 msgid "Upgraded Django to 1.8.9." msgstr "" + +#~ msgid "Contents" +#~ msgstr "Inhoudsopgave" + +#~ msgid "" +#~ "Support for ``MySQL`` has been " +#~ "**deprecated** since ``DSMR-reader v1.6`` " +#~ "and will be discontinued completely in" +#~ " a later release. Please use a " +#~ "PostgreSQL database instead. Users already " +#~ "running MySQL will be supported in " +#~ "migrating at a later moment." +#~ msgstr "" + +#~ msgid "" +#~ "API request should return HTTP 201 " +#~ "instead of HTTP 200 (`#211 " +#~ "`_)." +#~ msgstr "" + +#~ msgid "" +#~ "Docs: Explain settings/options (`#232 " +#~ "`_)." +#~ msgstr "" +#~ "De ondersteuning voor ``Python 3.3`` is" +#~ " **vervallen** wegens de Django upgrade " +#~ "(`#103 `_)." + diff --git a/docs/locale/nl/LC_MESSAGES/contributing.mo b/docs/locale/nl/LC_MESSAGES/contributing.mo index af93eb7b484219b4e5f97506a0cd3ac3a37accb7..a2a72b6671c1404a2ed5d7d5cb414b927a6a47a4 100644 GIT binary patch delta 406 zcmZ|IKTE?v7zXe+v1zqf?CMZ^f;uQ^F9B&SI9Nrxh<^qb2TjwnoULg{lS*+=@e33V zM?XbocQzgH z1iO?%ure8R|BZUoE|<5wAv+hM)pXnr>jg}DeiSmb7lKRmOSEuC8&5^X$RCc_aq1FMFQ3gW4Li xxm7Va_BNPRsjb`bNoqk;??zV*jkDFdyl4eZTd=Meh(LJ%|EG$2A-+yOXx~-4QxE_E delta 360 zcmYMuze~eF6bJBkHEA^}b`f!Cd4i)q8cY|#!9jEr7uR|wXBwJ@kffGO{TC{?I5{{u zn^kv59Uc2u6gR(31RuP7?uEPW-Ot9fIo+MS5z!1iKtBnhHE7j{mf;p$hYUa90X%_o zn85B5(I?Klz#it@ta83#6Z2WU%DIM%oE}`5c!;DGQnR2aMlk}_D6xI^s_j8n1%XFY!-82)hv6zW3%lXJGNdm+W(_d W92sq)-_09+Wrn&{-!9JUui_W|V@5&% diff --git a/docs/locale/nl/LC_MESSAGES/contributing.po b/docs/locale/nl/LC_MESSAGES/contributing.po index 96d55438c..bf5984338 100644 --- a/docs/locale/nl/LC_MESSAGES/contributing.po +++ b/docs/locale/nl/LC_MESSAGES/contributing.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: DSMR Reader v1.x\n" "Report-Msgid-Bugs-To: Dennis Siemensma \n" -"POT-Creation-Date: 2017-01-01 14:41+0100\n" -"PO-Revision-Date: 2017-01-01 14:44+0100\n" +"POT-Creation-Date: 2017-02-18 00:28+0100\n" +"PO-Revision-Date: 2017-02-19 17:52+0100\n" "Last-Translator: Dennis Siemensma \n" "Language-Team: Dennis Siemensma \n" "MIME-Version: 1.0\n" @@ -26,14 +26,13 @@ msgid "Would you like to contribute or help this project in any way?" msgstr "Wil je bijdragen aan dit project? Kijk dan hieronder hoe je kunt helpen." #: ../../contributing.rst:7 -msgid "Feedback" -msgstr "Feedback" +msgid "Feedback / Bugs / Contact" +msgstr "Feedback / Bugs / Contact" #: ../../contributing.rst:8 msgid "" -"All feedback and any input is, as always, very much appreciated! It doesn't " -"matter whether you run into problems getting started in this guide or just " -"want to get in touch, just fire away!" +"Any feedback or input is appreciated. It doesn't matter whether you run into " +"problems or just want to get in touch, just fire away!" msgstr "" "Het maakt niet uit of je ergens tegenaan loopt of gewoon in contact wil komen, " "vraag maar raak!" @@ -67,3 +66,6 @@ msgid "" msgstr "" "Tot slot, zorg ervoor dat pull requests altijd naar de ``development`` branch " "wijzen en niet de ``master``." + +#~ msgid "Feedback" +#~ msgstr "Feedback" diff --git a/docs/locale/nl/LC_MESSAGES/credits.mo b/docs/locale/nl/LC_MESSAGES/credits.mo index e04f294a5ef3469055a5e63ffbee58501226a6f0..b7415e7adffc8291c5e8c2ba9f386ab4b4982934 100644 GIT binary patch delta 213 zcmaFN`I)``o)F7a1|VPqVi_Rz0b*_-t^r~YSOLTuK)e!&y@2=<5UT*OEF%L03y^jK z()vK!9Y`++;&LFC0`ldVA?mGwv^9|53Zy}H90bx@K>7rb1}aqp3xW(n224;6Pz@Nc vPQ0r-S%|T8@=3;Zyym(FM!JR;3I+yNMi!e}m@F89Qr?sKS)3>DV9^EuH1HWM delta 451 zcmYk1F-yZh6vxx1+Eyq+M{#(AgGg%QB1I=Dh^T|;s=|@H>S4T;+%-iPK@jIs`~VK( zB6M(ZaBvXB(Jvs1AHm7Z|D}pP^5b`pm;B%5v-nXyd94;M98?)hf)G@|4Y2hFrolTX zg0Y%UCj3OC-7R9WBXF?s#a_!97>~mFX_@o#6mNv*f0qdQo_2; zfg!WcGNDKYtOC{^$ri>(9tlldj-pv-D{h&tNVvb88&u|N{v00i{RQ8@&F34rza8uS zGq=eramR)qu##$z4%rZ=tW1X^9&Ry`bsgJHA_IG-R45Ahm`VR^@~A76VotJ=iMcJb LM%ur-Jh|RCJsM+9 diff --git a/docs/locale/nl/LC_MESSAGES/credits.po b/docs/locale/nl/LC_MESSAGES/credits.po index fe22c55bb..6d9a7031f 100644 --- a/docs/locale/nl/LC_MESSAGES/credits.po +++ b/docs/locale/nl/LC_MESSAGES/credits.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: DSMR Reader v1.x\n" "Report-Msgid-Bugs-To: Dennis Siemensma \n" -"POT-Creation-Date: 2016-01-01 00:00+0100\n" +"POT-Creation-Date: 2017-02-18 00:28+0100\n" "PO-Revision-Date: 2017-01-01 00:00+0100\n" "Last-Translator: Dennis Siemensma \n" "Language-Team: Dennis Siemensma \n" @@ -18,8 +18,8 @@ msgstr "" "Generated-By: Babel 2.3.4\n" #: ../../credits.rst:2 -msgid "Credits" -msgstr "Credits" +msgid "Credits / Hall of Fame" +msgstr "" #: ../../credits.rst:6 msgid "Special thanks for supplying code contributions" @@ -82,11 +82,15 @@ msgid "\"`WatskeBart `_\"" msgstr "" #: ../../credits.rst:29 -msgid "Software" +#, fuzzy +msgid "Software used" msgstr "Software" #: ../../credits.rst:30 -msgid "Please note and respect their licences, if any, as well." +#, fuzzy +msgid "" +"Please note and respect their licences as well, if any. Credits to the " +"following software and projects:" msgstr "" "Houd rekening met eventuele licenties/restricties van deze software, " "wanneer van toepassing." @@ -130,66 +134,78 @@ msgid "" msgstr "" #: ../../credits.rst:50 -msgid "`Favicon `_" +msgid "" +"Favicon made by `Freepik `_ from `flaticon.com " +"`_" msgstr "" #: ../../credits.rst:52 -msgid "`Bootstrap-datepicker `_" +msgid "`Real Favicon Generator `_" msgstr "" #: ../../credits.rst:54 -msgid "`Github `_" +msgid "`Bootstrap-datepicker `_" msgstr "" #: ../../credits.rst:56 -msgid "`TravisCI `_" +msgid "`Github `_" msgstr "" #: ../../credits.rst:58 -msgid "`Codecov `_" +msgid "`TravisCI `_" msgstr "" #: ../../credits.rst:60 -msgid "`Read The Docs `_" +msgid "`Codecov `_" msgstr "" #: ../../credits.rst:62 -msgid "`MW `_" +msgid "`Read The Docs `_" msgstr "" #: ../../credits.rst:64 +msgid "`MW `_" +msgstr "" + +#: ../../credits.rst:66 msgid "" "`Full Page Screen Capture `_" msgstr "" -#: ../../credits.rst:66 +#: ../../credits.rst:68 msgid "`Buienradar `_" msgstr "" -#: ../../credits.rst:70 +#: ../../credits.rst:72 msgid "Misc" msgstr "Overig" -#: ../../credits.rst:72 +#: ../../credits.rst:74 msgid "Dutch Smart Meter reading specifications, data cables, examples and hints:" msgstr "Dutch Smart Meter reading specifications, data cables, examples and hints:" -#: ../../credits.rst:74 +#: ../../credits.rst:76 msgid "`Gé Janssen `_" msgstr "" -#: ../../credits.rst:76 +#: ../../credits.rst:78 msgid "" "`Joost van der Linde (smartmeterdashboard) " "`_" msgstr "" -#: ../../credits.rst:78 +#: ../../credits.rst:80 msgid "`SOS Solutions `_" msgstr "" -#: ../../credits.rst:80 +#: ../../credits.rst:82 msgid "`Nico Di Rocco `_" msgstr "" +#~ msgid "`Favicon `_" +#~ msgstr "" + +#~ msgid "Credits" +#~ msgstr "Credits" + diff --git a/docs/locale/nl/LC_MESSAGES/faq.mo b/docs/locale/nl/LC_MESSAGES/faq.mo index 3199432c3d246cf22f29163754f9e43586aa8291..5e255a9c2a12184651615c8bcb127e019ebcc714 100644 GIT binary patch delta 1622 zcmZA0OKclO7{Kw*C3fh8P$wZt6GA7C22z|*+oVd?W# zJCAQBmyQPBm=C=2YOy{b^2=J01rfQjPUI}Ud6P&3?fE*9&xl{RS>!gHST9nKv)F=j z*pA0g;S#ptay9-9yNK(;BHJ*AgP6gM_)b`g@*0(|X?PZ=82tnjub?J=zENbD_*Yyc z?roxuKVlTWY!>OnKhP|wg&(>~6j$-xI9?#$wV|@WNUO*+@owCMORYs#M8`Uoy@Q5{ zTSXi^jCs6*W&)dS&f`2D!YHlQa=kRXkm-nd*@!~vkjM5et`3mE>fPdk)O#C{% zOT;r<$p-Ode3y9dAiKm`ZWvvpmcdx73?ru}X{^VCSj%_EaUH%*T4T&FOT!FGhl^;= zaDoG~=x_q>B@T^R2p%7;WavelC*FCVNRaP-z!Cguhe($8w);h1!b6zD zX3k|24`PWd%QBS()Z>-Z1}7?)?t9!r`(-qD;<3rnP)*N@_CtN`~sv68SC@lvY%cp_^ zq4Mu*&jpLwoa1^aJE^>VS|u#cQZr5=lTeD$Gl2qb-&u>DbI1zYWLiu4?m!y z11g)c3!cu?s#5+i%GQ>fnNx9IWilzpR<5=Z44#juS=Y%j-i(vYxjLWM2{moaqzg^C zh@zjR9i>m10 zP<%`2LieTewM~nm@`sVmP;pXw)x~I6+vcL!fdx=89_0&E_BLRG?U8NZ>{gg$v2-u9j%l!_mS#2^%#T(QAnLT2r oFQh#G%cSip=Kw3OVKE{I~zx{h8QE!}Z;_j86sr0W69ol>h($ delta 1326 zcmX}sSx8h-9LMqBq%)drE|u9fS4SsX#&pcG$+FE<=pl%x2MwlXvcP6qMnVe4mY2d7 zxfO(vkUc~zHBw1|&`Tf`l?4$*R!|T15ERuzQQtFTT{!bO|9j89_niOv&pp@W_;$i^ z>U2C)(#J7Uu0#5QJ;Z6_q?g!>d7M8mUK$`iH9?w*>#`Y-QJjK@a0Ygxh5a}UUya1y z(LTA<7cD$rAZ@_`Y{sIgac086j;Yd0PV_VFDE`8|*g8G+f?@0; zPGgxz@eKY#H|ZG7{nJ@R6S3El+VL=M#NW6SHxx2Cw9&?yMN%K$iqk2k(?WhWV<)b{ zPxyof&*$P2VtJ) z)XrNpq~2_Rv!!1sTwR%ZT5xfgM;#a1t+|*#duU zDl^-$i`czfa&q5Iti?Mk*e1^ZSScOHF#Ea-zhVQ1RD3ubg43!ThNf()a)*lM2e971%y!ev^lusg*f2vYsr^Vx*KrQj*^QH&S!S zEzLs8Dfz81wPFslHRdQxk^JRzA^WLwVxrGk<#I)0;Ye(6;=`C>XQDZ`G{+SR?`n;< zCptX|M^=TeywdWQ2deybV~LeH5>(r}OTLw^4Mtkpf-T{I6=}`d\n" -"POT-Creation-Date: 2017-01-03 20:52+0100\n" -"PO-Revision-Date: 2017-01-03 20:58+0100\n" +"POT-Creation-Date: 2017-02-16 15:58+0100\n" +"PO-Revision-Date: 2017-01-21 18:30+0100\n" "Last-Translator: Dennis Siemensma \n" "Language-Team: Dennis Siemensma \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.3.4\n" -"Language: nl\n" -"X-Generator: Poedit 1.8.7.1\n" #: ../../faq.rst:2 msgid "Frequently Asked Questions (FAQ)" msgstr "Veelgestelde vragen (FAQ)" -#: ../../faq.rst -msgid "Contents" -msgstr "Inhoud" - #: ../../faq.rst:10 msgid "How can I update my application?" msgstr "Hoe kan ik mijn applicatie bijwerken?" #: ../../faq.rst:11 msgid "" -"The version you are running is always based on the 'latest' version of the " -"application, called the `master` branch. Every once in a while there may be " -"updates. Since ``v1.5`` you can also easily check for updates by using the " -"application's Status page." +"The version you are running is always based on the 'latest' version of " +"the application, called the `master` branch. Every once in a while there " +"may be updates. Since ``v1.5`` you can also easily check for updates by " +"using the application's Status page." msgstr "" -"De versie die je draait is altijd gebaseerd op de 'laatste' versie van de " -"applicatie, ook wel de `master` branch genoemd. Met enige regelmaat zijn er " -"updates beschikbaar. Sinds ``v1.5`` kun je dit ook eenvoudig controleren op de " -"Status-pagina van de applicatie." +"De versie die je draait is altijd gebaseerd op de 'laatste' versie van de" +" applicatie, ook wel de `master` branch genoemd. Met enige regelmaat zijn" +" er updates beschikbaar. Sinds ``v1.5`` kun je dit ook eenvoudig " +"controleren op de Status-pagina van de applicatie." #: ../../faq.rst:16 msgid "" @@ -49,27 +43,28 @@ msgid "" "database**! :doc:`More information about backups can be found " "here`." msgstr "" -"Voordat je bijwerkt, **zorg ervoor dat je in ieder geval een recente back-up " -"van je database hebt**! :doc:`Meer informatie over back-ups kun je hier " -"vinden`." +"Voordat je bijwerkt, **zorg ervoor dat je in ieder geval een recente " +"back-up van je database hebt**! :doc:`Meer informatie over back-ups kun " +"je hier vinden`." #: ../../faq.rst:18 msgid "" -"You can update your application to the latest version by executing **deploy." -"sh**, located in the root of the project. Make sure to execute it while logged " -"in as the ``dsmr`` user::" +"You can update your application to the latest version by executing " +"**upgrade.sh**, located in the root of the project. Make sure to execute " +"it while logged in as the ``dsmr`` user::" msgstr "" -"Je kun je applicatie bijwerken door het script **deploy.sh** uit te voeren, " -"die in zich in de hoofdmap van het project bevindt. Zorg er wel voor dat je " -"ingelogd bent als ``dsmr`` gebruiker op de terminal::" +"Je kun je applicatie bijwerken door het script **upgrade.sh** uit te " +"voeren, die in zich in de hoofdmap van het project bevindt. Zorg er wel " +"voor dat je ingelogd bent als ``dsmr`` gebruiker op de terminal::" #: ../../faq.rst:23 msgid "" -"It will make sure to check, fetch and apply any changes released. Summary of " -"deployment script steps:" +"It will make sure to check, fetch and apply any changes released. Summary" +" of deployment script steps:" msgstr "" "Dit zorgt ervoor dat alle wijzigingen op een juiste volgorde worden " -"binnengehaald en toegepast. Een overzicht van wat dit uitrol-script exact doet:" +"binnengehaald en toegepast. Een overzicht van wat dit uitrol-script exact" +" doet:" #: ../../faq.rst:25 msgid "GIT pull (codebase update)." @@ -89,11 +84,11 @@ msgstr "Synchroniseert statische bestanden naar de Nginx map." #: ../../faq.rst:29 msgid "" -"Reload Gunicorn application server (web interface) and backend processes (such " -"as the datalogger)." +"Reload Gunicorn application server (web interface) and backend processes " +"(such as the datalogger)." msgstr "" -"Herlaadt de Gunicorn-applicatieserver (webinterface) en achtergrondprocessen " -"(zoals de datalogger)." +"Herlaadt de Gunicorn-applicatieserver (webinterface) en " +"achtergrondprocessen (zoals de datalogger)." #: ../../faq.rst:30 msgid "Clear any caches." @@ -109,42 +104,43 @@ msgstr "*Hoe kan ik mijn Dropbox-account koppelen voor de backups?*" #: ../../faq.rst:37 msgid "" -"Make sure you have a Dropbox-account or sign up for one. Now go to `Dropbox " -"Apps `_ and click **\"Create app\"** " -"in top right corner." +"Make sure you have a Dropbox-account or sign up for one. Now go to " +"`Dropbox Apps `_ and click " +"**\"Create app\"** in top right corner." msgstr "" -"Zorg allereerst dat je een Dropbox-account hebt. Ga vervolgens naar `Dropbox " -"Apps `_ en klik op **\"Create app\"** " -"rechtsbovenin." +"Zorg allereerst dat je een Dropbox-account hebt. Ga vervolgens naar " +"`Dropbox Apps `_ en klik op " +"**\"Create app\"** rechtsbovenin." #: ../../faq.rst:44 msgid "" -"Choose the following options: (1) **Dropbox API** and (2) **App folder**. Then " -"enter a name for your app (3), this will also be used as directory name within " -"the Apps-folder of your Dropbox." +"Choose the following options: (1) **Dropbox API** and (2) **App folder**." +" Then enter a name for your app (3), this will also be used as directory " +"name within the Apps-folder of your Dropbox." msgstr "" -"Kies de volgende opties: (1) **Dropbox API** en (2) **App folder**. Voer " -"vervolgens een naam voor je app in (3), deze wordt ook gebruikt als naam van " -"de submap binnen je Apps-folder in Dropbox." +"Kies de volgende opties: (1) **Dropbox API** en (2) **App folder**. Voer" +" vervolgens een naam voor je app in (3), deze wordt ook gebruikt als naam" +" van de submap binnen je Apps-folder in Dropbox." #: ../../faq.rst:51 msgid "" -"The app should be created in developer-mode. You can generate an access token " -"for yourself by clicking the **\"Generate\"** button somewhere below." +"The app should be created in developer-mode. You can generate an access " +"token for yourself by clicking the **\"Generate\"** button somewhere " +"below." msgstr "" -"The app is als het goed is nu aangemaakt in developer-modus. Je kunt nog een " -"toegangstoken genereren door op de knop **\"Generate\"** te klikken, die " -"verderop onderaan de pagina staat." +"The app is als het goed is nu aangemaakt in developer-modus. Je kunt nog " +"een toegangstoken genereren door op de knop **\"Generate\"** te klikken, " +"die verderop onderaan de pagina staat." #: ../../faq.rst:57 msgid "" -"Copy the generated access token to the DSMR-reader settings for the Dropbox-" -"configuration. The DSMR-reader application should sync any backups created " -"shortly." +"Copy the generated access token to the DSMR-reader settings for the " +"Dropbox-configuration. The DSMR-reader application should sync any " +"backups created shortly." msgstr "" -"Kopieer de gegenereerde toegangstoken naar de DSMR-reader instellingen onder " -"Dropbox-configuratie. DSMR-reader zou vrij vlot gemaakte backups moeten " -"uploaden naar je Dropbox-account." +"Kopieer de gegenereerde toegangstoken naar de DSMR-reader instellingen " +"onder Dropbox-configuratie. DSMR-reader zou vrij vlot gemaakte backups " +"moeten uploaden naar je Dropbox-account." #: ../../faq.rst:61 msgid "Mindergas.nl: Automated gas meter position export" @@ -156,39 +152,39 @@ msgstr "*Hoe kan ik mijn mindergas.nl-account koppelen?*" #: ../../faq.rst:64 msgid "" -"Make sure you have a Mindergas.nl-account or `signup for one `_. Now go to \"`Meterstand API `_\" and click on the button located below **" -"\"Authenticatietoken\"**." +"Make sure you have a Mindergas.nl-account or `signup for one " +"`_. Now go to \"`Meterstand API " +"`_\" and click on the button located" +" below **\"Authenticatietoken\"**." msgstr "" -"Zorg ervoor dat je een mindergas.nl-account hebt of `registreer je op hun " -"website `_. Ga nu naar \"`Meterstand " -"API `_\" en klik op de knop onder het " -"kopje **\"Authenticatietoken\"**." +"Zorg ervoor dat je een mindergas.nl-account hebt of `registreer je op hun" +" website `_. Ga nu naar " +"\"`Meterstand API `_\" en klik op de" +" knop onder het kopje **\"Authenticatietoken\"**." #: ../../faq.rst:71 msgid "" -"Copy the authentication token generated and paste in into the DSMR-reader " -"settings for the Mindergas.nl-configuration. Obviously the export only works " -"when there are any gas readings at all and you have ticked the 'export' " -"checkbox in the Mindergas.nl-configuration as well." +"Copy the authentication token generated and paste in into the DSMR-reader" +" settings for the Mindergas.nl-configuration. Obviously the export only " +"works when there are any gas readings at all and you have ticked the " +"'export' checkbox in the Mindergas.nl-configuration as well." msgstr "" -"Kopieer de gegenereerde authenticatietoken in de DSMR-reader instellingen " -"onder Mindergas.nl-configuratie. Vanzelfsprekend werkt deze feature alleen " -"wanneer er gas gemeten wordt, en wanneer je de optie 'Exporteer gegevens naar " -"MinderGas' aangevinkt hebt in dezelfde configuratie." +"Kopieer de gegenereerde authenticatietoken in de DSMR-reader instellingen" +" onder Mindergas.nl-configuratie. Vanzelfsprekend werkt deze feature " +"alleen wanneer er gas gemeten wordt, en wanneer je de optie 'Exporteer " +"gegevens naar MinderGas' aangevinkt hebt in dezelfde configuratie." #: ../../faq.rst:76 msgid "" "Please note that due to policies of mindergas.nl it's not allowed to " "retroactively upload meter positions using the API. Therefor this is not " -"supported by the application. You can however, enter them manually on their " -"website." +"supported by the application. You can however, enter them manually on " +"their website." msgstr "" "N.B.: Wegens het beleid van mindergas.nl is het niet toegestaan om met " -"terugwerkende kracht meterstanden door te geven via de API. De applicatie " -"ondersteunt dat om die reden niet. Je kunt oude meterstanden echter wel via " -"hun website handmatig invoeren, indien gewenst." +"terugwerkende kracht meterstanden door te geven via de API. De applicatie" +" ondersteunt dat om die reden niet. Je kunt oude meterstanden echter wel " +"via hun website handmatig invoeren, indien gewenst." #: ../../faq.rst:81 msgid "Usage notification: Daily usage statistics on your smartphone" @@ -200,13 +196,15 @@ msgstr "*Welke services voor het sturen van notificaties worden ondersteund?*" #: ../../faq.rst:84 msgid "" -"Currently, two mobile platforms are supported: Android and iOS. The supported " -"app for Android is `NotifyMyAndroid `_. The " -"supported app for iOS is `Prowl `_." +"Currently, two mobile platforms are supported: Android and iOS. The " +"supported app for Android is `NotifyMyAndroid " +"`_. The supported app for iOS is `Prowl " +"`_." msgstr "" "Op dit moment worden twee platforms ondersteund: Android en iOS. De " -"ondersteunde app voor Android is `NotifyMyAndroid `_. De ondersteunde app voor iOS is `Prowl `_." +"ondersteunde app voor Android is `NotifyMyAndroid " +"`_. De ondersteunde app voor iOS is " +"`Prowl `_." #: ../../faq.rst:89 msgid "*How do I setup usage notifications?*" @@ -215,32 +213,34 @@ msgstr "*Hoe stel ik verbruiksnotificaties in?*" #: ../../faq.rst:91 msgid "" "Make sure you either have NotifyMyAndroid or Prowl installed on your " -"smartphone. If you don't, visit your platforms app store to download the app " -"and sign up for an account. Then, make sure to get your API key from the " -"notificationservice that you prefer. For instruction on obtaining the API key, " -"please read below." +"smartphone. If you don't, visit your platforms app store to download the " +"app and sign up for an account. Then, make sure to get your API key from " +"the notificationservice that you prefer. For instruction on obtaining the" +" API key, please read below." msgstr "" "Zorg ervoor dat je NotifyMyAndroid of Prowl hebt geïnstalleerd op je " "smartphone. Als dat niet het geval is, bezoek dan de app store van je " -"platform, download de gewenste app en maak daarvoor een account. Daarna haal " -"je de API key voor de notificatieservice die je wilt gebruiken op. Om te lezen " -"hoe dat werkt, lees dan de instructies bij de volgende kopjes." +"platform, download de gewenste app en maak daarvoor een account. Daarna " +"haal je de API key voor de notificatieservice die je wilt gebruiken op. " +"Om te lezen hoe dat werkt, lees dan de instructies bij de volgende " +"kopjes." #: ../../faq.rst:93 msgid "" "In the DSMR-reader settings for the Usagenotifications, tick the Send " -"Notifications checkbox and select the notification service you want to use. " -"Then copy the API key from the notification service and paste in into the the " -"textbox for the API key. When you save these settings, your first notification " -"should be sent after midnight. Don't worry, the notification will be sent with " -"low priority and will not wake you up." -msgstr "" -"In de DSMR-reader instellingen voor de Verbruiksnotificaties zet je een vinkje " -"bij Stuur Notificaties en selecteer daaronder welke notificatieservice je wilt " -"gebruiken. Kopieeër daarna de API key van de notificatieservice en plak deze " -"in het tekstveld voor de API key. Als je deze instellingen opslaat zul je na " -"middernacht je eerste notificatie ontvangen. Geen nood, de notificatie wordt " -"altijd verstuurd met lage prioriteit, deze maakt je dus niet wakker." +"Notifications checkbox and select the notification service you want to " +"use. Then copy the API key from the notification service and paste in " +"into the the textbox for the API key. When you save these settings, your " +"first notification should be sent after midnight. Don't worry, the " +"notification will be sent with low priority and will not wake you up." +msgstr "" +"In de DSMR-reader instellingen voor de Verbruiksnotificaties zet je een " +"vinkje bij Stuur Notificaties en selecteer daaronder welke " +"notificatieservice je wilt gebruiken. Kopieeër daarna de API key van de " +"notificatieservice en plak deze in het tekstveld voor de API key. Als je " +"deze instellingen opslaat zul je na middernacht je eerste notificatie " +"ontvangen. Geen nood, de notificatie wordt altijd verstuurd met lage " +"prioriteit, deze maakt je dus niet wakker." #: ../../faq.rst:96 msgid "*How do I obtain my API key for NotifyMyAndroid?*" @@ -248,27 +248,28 @@ msgstr "*Hoe haal ik de API key op voor NotifyMyAndroid?*" #: ../../faq.rst:98 msgid "" -"After you have downloaded NotifyMyAndroid and signed up for an account you " -"should be able to `login to your NotifyMyAndroid account `_. Now go to \"`My Account `_\", you should see an overview of your " -"current API keys if you have any. To create an API key for the DSMR-reader, " -"please click **\"Generate New Key\"**." +"After you have downloaded NotifyMyAndroid and signed up for an account " +"you should be able to `login to your NotifyMyAndroid account " +"`_. Now go to \"`My Account " +"`_\", you should see an " +"overview of your current API keys if you have any. To create an API key " +"for the DSMR-reader, please click **\"Generate New Key\"**." msgstr "" -"Nadat je NotifyMyAndroid hebt gedownload en een account hebt aangemaakt zou je " -"moeten kunnen `inloggen op je NotifyMyAndroid-account `_. Ga nu naar \"`My Account `_\" om een overzicht van je account de API " -"keys te krijgen als je deze al hebt. Om een API key voor de DSMR-reader te " -"genereren klik je op **\"Generate New Key\"**." +"Nadat je NotifyMyAndroid hebt gedownload en een account hebt aangemaakt " +"zou je moeten kunnen `inloggen op je NotifyMyAndroid-account " +"`_. Ga nu naar \"`My Account " +"`_\" om een overzicht van je" +" account de API keys te krijgen als je deze al hebt. Om een API key voor " +"de DSMR-reader te genereren klik je op **\"Generate New Key\"**." #: ../../faq.rst:105 ../../faq.rst:121 msgid "" -"When a new key is generated, you will see it immediatly. Your key is listed " -"like in the screenshot below (the red box marks your API key)." +"When a new key is generated, you will see it immediatly. Your key is " +"listed like in the screenshot below (the red box marks your API key)." msgstr "" -"Als er een nieuwe key is gegenereerd, zie je deze direct. De key is te vinden " -"zoals in onderstaande screenshot (er staat een rood kader om de key)." +"Als er een nieuwe key is gegenereerd, zie je deze direct. De key is te " +"vinden zoals in onderstaande screenshot (er staat een rood kader om de " +"key)." #: ../../faq.rst:112 msgid "*How do I obtain my API key for Prowl?*" @@ -276,18 +277,20 @@ msgstr "*Hoe haal ik de API key op voor Prowl?*" #: ../../faq.rst:114 msgid "" -"After you have downloaded Prowl and signed up for an account you should be " -"able to `login to your Prowl account `_. " -"Now go to \"`API Keys `_\", you " -"should see an overview of your current API keys if you have any. To create an " -"API key for the DSMR-reader, input a name and click **\"Generate Key\"**." -msgstr "" -"Nadat je Prowl hebt gedownload en een account hebt aangemaakt zou je moeten " -"kunnen `inloggen op je Prowl-account `_. " -"Ga nu naar \"`API Keys `_\" om een " -"overzicht van je API keys te krijgen als je deze al hebt. Om een API key voor " -"de DSMR-reader te genereren geef je een naam op en klik je op **\"Generate Key" -"\"**." +"After you have downloaded Prowl and signed up for an account you should " +"be able to `login to your Prowl account " +"`_. Now go to \"`API Keys " +"`_\", you should see an " +"overview of your current API keys if you have any. To create an API key " +"for the DSMR-reader, input a name and click **\"Generate Key\"**." +msgstr "" +"Nadat je Prowl hebt gedownload en een account hebt aangemaakt zou je " +"moeten kunnen `inloggen op je Prowl-account " +"`_. Ga nu naar \"`API Keys " +"`_\" om een overzicht van je " +"API keys te krijgen als je deze al hebt. Om een API key voor de DSMR-" +"reader te genereren geef je een naam op en klik je op **\"Generate " +"Key\"**." #: ../../faq.rst:129 msgid "I only pay for a single electricity tariff but I see two!" @@ -295,28 +298,28 @@ msgstr "Ik betaal voor een enkel tarief maar ik zie er twee!" #: ../../faq.rst:130 msgid "" -"DSMR (and your energy supplier) always read both high and low tariff from your " -"meter. It's possible however that you are only paying for a single tariff. In " -"that case your energy supplier will simply merge both high and low tariffs to " -"make it look like you have a single one." +"DSMR (and your energy supplier) always read both high and low tariff from" +" your meter. It's possible however that you are only paying for a single " +"tariff. In that case your energy supplier will simply merge both high and" +" low tariffs to make it look like you have a single one." msgstr "" -"DSMR (en je energieleverancier) lezen altijd zowel hoog als laag tarief van je " -"meter uit. Het is desondanks mogelijk dat je betaalt voor slechts één tarief. " -"In dat geval voegt jouw energieleverancier het hoge en lage tarief samen zodat " -"het lijkt alsof je een enkel tarief hebt." +"DSMR (en je energieleverancier) lezen altijd zowel hoog als laag tarief " +"van je meter uit. Het is desondanks mogelijk dat je betaalt voor slechts " +"één tarief. In dat geval voegt jouw energieleverancier het hoge en lage " +"tarief samen zodat het lijkt alsof je een enkel tarief hebt." #: ../../faq.rst:134 msgid "" -"This application displays separate tariffs by default, but supports merging " -"them to a single one as well. Just make sure that you apply the **same price " -"to both electricity 1 and 2** and enable the option ``Merge electricity " -"tariffs`` in the frontend configuration." +"This application displays separate tariffs by default, but supports " +"merging them to a single one as well. Just make sure that you apply the " +"**same price to both electricity 1 and 2** and enable the option ``Merge " +"electricity tariffs`` in the frontend configuration." msgstr "" "Deze applicatie weergeeft standaard gescheiden tarieven, maar heeft wel " -"ondersteuning om ze samen te voegen (net zoals je energieleverancier doet). " -"Zorg er wel voor dat je **dezelfde prijs invult bij hoog en laag tarief voor " -"elektriciteit** en dat je de optie ``Voeg tarieven samen`` aanzet in de " -"interfaceconfiguratie." +"ondersteuning om ze samen te voegen (net zoals je energieleverancier " +"doet). Zorg er wel voor dat je **dezelfde prijs invult bij hoog en laag " +"tarief voor elektriciteit** en dat je de optie ``Voeg tarieven samen`` " +"aanzet in de interfaceconfiguratie." #: ../../faq.rst:139 msgid "I want to see the load of each electricity phase as well" @@ -324,17 +327,17 @@ msgstr "Ik wil het elektriciteitsverbruik per fase ook kunnen zien" #: ../../faq.rst:140 msgid "" -"Since ``DSMR-reader v1.5`` it's possible to track your ``P+`` (consumption) " -"phases as well. You will need to enable this in the ``Datalogger " -"configuration``. There is a setting called ``Track electricity phases``. When " -"active, this will log the current usage of those phases and plot these on the " -"Dashboard page." +"Since ``DSMR-reader v1.5`` it's possible to track your ``P+`` " +"(consumption) phases as well. You will need to enable this in the " +"``Datalogger configuration``. There is a setting called ``Track " +"electricity phases``. When active, this will log the current usage of " +"those phases and plot these on the Dashboard page." msgstr "" "Sinds ``DSMR-reader v1.5`` is het mogelijk om je ``P+`` (verbruik) " "elektriciteitsfasen in te zien. Dit is een aparte optie die je zelf moet " -"inschakelen in ``Dataloggerconfiguratie``. De instelling heet daar ``Houd " -"elektriciteitsfasen bij``. Zodra ingeschakeld, zal de applicatie het verbruik " -"per fase vastleggen in tonen in een grafiek in het Dashboard." +"inschakelen in ``Dataloggerconfiguratie``. De instelling heet daar ``Houd" +" elektriciteitsfasen bij``. Zodra ingeschakeld, zal de applicatie het " +"verbruik per fase vastleggen in tonen in een grafiek in het Dashboard." #: ../../faq.rst:143 msgid "Please keep in mind:" @@ -342,28 +345,29 @@ msgstr "Houd in gedachten:" #: ../../faq.rst:145 msgid "" -"This will **not work retroactively**. The datalogger always discards all data " -"not used." +"This will **not work retroactively**. The datalogger always discards all " +"data not used." msgstr "" -"Dit werkt **niet met terugwerkende kracht**. De datalogger gooit namelijk alle " -"gegevens weg die niet nodig zijn." +"Dit werkt **niet met terugwerkende kracht**. De datalogger gooit namelijk" +" alle gegevens weg die niet nodig zijn." #: ../../faq.rst:146 msgid "" -"This feature will only work when your smart meter is connected to **three " -"phases**. Even when having the setting enabled." +"This feature will only work when your smart meter is connected to **three" +" phases**. Even when having the setting enabled." msgstr "" "Deze feature werkt alleen wanneer je slimme meter ook daadwerkelijk is " "aangesloten op **drie fasen**. Zelfs wanneer de optie is ingeschakeld." #: ../../faq.rst:147 msgid "" -"When having tracking phases enabled, you should see a button in the Dashboard " -"called ``Display electricity phases``. Click on it to show the graph." +"When having tracking phases enabled, you should see a button in the " +"Dashboard called ``Display electricity phases``. Click on it to show the " +"graph." msgstr "" -"Wanneer het bijhouden van de fasen is ingeschakeld, zie je op het Dashboard " -"een knop genaamd ``Toon elektriciteitsfasen``. Klik die aan om de grafiek te " -"tonen." +"Wanneer het bijhouden van de fasen is ingeschakeld, zie je op het " +"Dashboard een knop genaamd ``Toon elektriciteitsfasen``. Klik die aan om " +"de grafiek te tonen." #: ../../faq.rst:149 msgid "You should see something similar to:" @@ -375,16 +379,16 @@ msgstr "Prijzen opnieuw berekenen met terugwerkende kracht" #: ../../faq.rst:158 msgid "" -"*I've adjusted my energy prices but there are no changes! How can I regenerate " -"them with my new prices?*" +"*I've adjusted my energy prices but there are no changes! How can I " +"regenerate them with my new prices?*" msgstr "" -"*Ik heb zojuist mijn energieprijzen aangepast, maar ik zie geen verschil! Hoe " -"kan ik de nieuwe prijzen doorvoeren?*" +"*Ik heb zojuist mijn energieprijzen aangepast, maar ik zie geen verschil!" +" Hoe kan ik de nieuwe prijzen doorvoeren?*" #: ../../faq.rst:160 msgid "" -"Statistics for each day are generated once, the day after. However, you can " -"flush your statistics by executing:" +"Statistics for each day are generated once, the day after. However, you " +"can flush your statistics by executing:" msgstr "" "Dagstatistieken worden dagelijks eenmalig gegenereerd. Het is echter wel " "mogelijk om deze te resetten door het volgende te doen:" @@ -395,11 +399,12 @@ msgstr "``./manage.py dsmr_stats_clear_statistics --ack-to-delete-my-data``" #: ../../faq.rst:164 msgid "" -"The application will delete all statistics and (slowly) regenerate them in the " -"background. Just make sure the source data is still there." +"The application will delete all statistics and (slowly) regenerate them " +"in the background. Just make sure the source data is still there." msgstr "" -"De applicatie verwijdert alle statistieken en genereert ze (langzaam) weer op " -"de achtergrond. Zorg er wel voor dat alle brongegevens intact zijn." +"De applicatie verwijdert alle statistieken en genereert ze (langzaam) " +"weer op de achtergrond. Zorg er wel voor dat alle brongegevens intact " +"zijn." #: ../../faq.rst:168 msgid "I'm not seeing any gas readings" @@ -407,15 +412,15 @@ msgstr "Ik zie geen gasverbruik" #: ../../faq.rst:169 msgid "" -"Please make sure that your meter supports reading gas consumption and that " -"you've waited for a few hours for any graphs to render. The gas meter " -"positions are only be updated once per hour (for DSMR v4). The Status page " -"will give you insight in this as well." +"Please make sure that your meter supports reading gas consumption and " +"that you've waited for a few hours for any graphs to render. The gas " +"meter positions are only be updated once per hour (for DSMR v4). The " +"Status page will give you insight in this as well." msgstr "" "Wees er allereerst zeker van dat je slimme meter uberhaupt gasverbruik " -"registreert, en dat je een paar uur hebt gewacht. De gasmeterstanden worden " -"sowieso slechts een keer per uur bijgewerkt (voor DSMR v4). De Status-pagina " -"geeft je hier overigens ook inzicht in." +"registreert, en dat je een paar uur hebt gewacht. De gasmeterstanden " +"worden sowieso slechts een keer per uur bijgewerkt (voor DSMR v4). De " +"Status-pagina geeft je hier overigens ook inzicht in." #: ../../faq.rst:175 msgid "How do I restore a database backup?" @@ -423,21 +428,21 @@ msgstr "Hoe zet ik een databaseback-up terug?" #: ../../faq.rst:179 msgid "" -"Restoring a backup will replace any existing data stored in the database and " -"is irreversible!" +"Restoring a backup will replace any existing data stored in the database " +"and is irreversible!" msgstr "" -"Het herstellen van een back-up vervangt de bestaande data in de database en is " -"onomkeerbaar!" +"Het herstellen van een back-up vervangt de bestaande data in de database " +"en is onomkeerbaar!" #: ../../faq.rst:183 msgid "" -"Do you need a complete reinstall of DSMR-reader as well? Then please :doc:" -"`follow the install guide` and restore the database backup " -"**using the notes at the end of chapter 1**." +"Do you need a complete reinstall of DSMR-reader as well? Then please " +":doc:`follow the install guide` and restore the database " +"backup **using the notes at the end of chapter 1**." msgstr "" -"Heb je tevens een complete herinstallatie van DSMR-reader nodig? :doc:`Volg " -"dan de installatiehandleiding` en herstel de databaseback-up " -"volgens **de notities aan het einde van hoofdstuk 1**." +"Heb je tevens een complete herinstallatie van DSMR-reader nodig? " +":doc:`Volg dan de installatiehandleiding` en herstel de " +"databaseback-up volgens **de notities aan het einde van hoofdstuk 1**." #: ../../faq.rst:186 msgid "Only want to restore the database?" @@ -445,53 +450,67 @@ msgstr "Wil je alleen een databaseback-up terugzetten?" #: ../../faq.rst:188 msgid "" -"This asumes you are still running the same application version as the backup " -"was created in." +"This asumes you are still running the same application version as the " +"backup was created in." msgstr "" -"Dit gaat er overigens wel van uit dat je dezelfde applicatie-versie draait als " -"waarmee de back-up is gemaakt." +"Dit gaat er overigens wel van uit dat je dezelfde applicatie-versie " +"draait als waarmee de back-up is gemaakt." #: ../../faq.rst:190 msgid "" -"Stop the application first with ``sudo supervisorctl stop all``. This will " -"disconnect it from the database as well." +"Stop the application first with ``sudo supervisorctl stop all``. This " +"will disconnect it from the database as well." msgstr "" -"Stop als eerste de applicatie met ``sudo supervisorctl stop all``. Dit zorgt " -"er ook voor dat de databaseverbinding van de applicatie verdwijnt." +"Stop als eerste de applicatie met ``sudo supervisorctl stop all``. Dit " +"zorgt er ook voor dat de databaseverbinding van de applicatie verdwijnt." #: ../../faq.rst:192 +msgid "" +"Importing the data could take a long time. It took MySQL 15 minutes to " +"import nearly 3 million readings, from a compressed backup, on a " +"RaspberryPi 3." +msgstr "" +"Het importeren van de gegevens kan enige tijd in beslag nemen. Op MySQL " +"duurt het ongeveer een kwartier om 3 miljoen metingen te importeren, " +"vanuit een gecomprimeerde back-up op een RaspberryPi 3." + +#: ../../faq.rst:194 msgid "For **PostgreSQL** restores::" msgstr "Voor herstellen van **PostgreSQL**::" -#: ../../faq.rst:206 +#: ../../faq.rst:208 msgid "For **MySQL** restores::" msgstr "Voor herstellen van **MySQL**::" -#: ../../faq.rst:220 +#: ../../faq.rst:222 msgid "Start the application again with ``sudo supervisorctl start all``." msgstr "Start de applicatie weer met ``sudo supervisorctl start all``." -#: ../../faq.rst:224 +#: ../../faq.rst:226 msgid "" "In case the version differs, you can try forcing a deployment reload by: " "``sudo su - dsmr`` and then executing ``./post-deploy.sh``." msgstr "" -"Mocht de versie toch verschillen, dan kun je proberen om de applicatie te " -"herladen. Log in met: ``sudo su - dsmr`` en voer vervolgens ``./post-deploy." -"sh`` uit." +"Mocht de versie toch verschillen, dan kun je proberen om de applicatie te" +" herladen. Log in met: ``sudo su - dsmr`` en voer vervolgens ``./post-" +"deploy.sh`` uit." -#: ../../faq.rst:228 +#: ../../faq.rst:230 msgid "Feature/bug report" msgstr "Verzoek/fout melden" -#: ../../faq.rst:229 +#: ../../faq.rst:231 msgid "*How can I propose a feature or report a bug I've found?*" msgstr "*Hoe kan ik een verzoek indienen of een fout melden?*" -#: ../../faq.rst:233 +#: ../../faq.rst:235 msgid "" "`Just create a ticket at Github `_." msgstr "" -"`Maak een ticket aan op Github `_." +"`Maak een ticket aan op Github `_." + +#~ msgid "Contents" +#~ msgstr "Inhoud" + diff --git a/docs/locale/nl/LC_MESSAGES/installation.mo b/docs/locale/nl/LC_MESSAGES/installation.mo index a67342935b5bd16ddccac5f89fdc0e0d27923158..5c5a79d24f4bdf16122fcdaa9ed127da5b582ac5 100644 GIT binary patch delta 4839 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 delta 4994 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\n" -"POT-Creation-Date: 2017-01-03 19:26+0100\n" -"PO-Revision-Date: 2017-01-03 19:29+0100\n" -"Last-Translator: Dennis Siemensma \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=iso-8859-1\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.3.4\n" -"Language: nl\n" -"X-Generator: Poedit 1.8.7.1\n" +# Copyright (C) 2016, Dennis Siemensma +# This file is distributed under the same license as the DSMR Reader +# package. +# #: ../../installation.rst:2 msgid "Installation" msgstr "Installatie" #: ../../installation.rst:6 -msgid "" -"The installation guide may take about *half an hour max* (for raspberryPi 2/3), " -"but it greatly depends on your Linux skills and whether you need to understand " -"every step described in this guide." -msgstr "" -"Het installeren duurt naar verwachting zo'n *half uur* (op een RaspberryPi " -"2/3), maar hangt natuurlijk ook af van je eigen vaardigheid op de command line." - -#: ../../installation.rst -msgid "Contents" -msgstr "Inhoudsopgave" +msgid "The installation guide may take about *half an hour max* (for raspberryPi 2/3), but it greatly depends on your Linux skills and whether you need to understand every step described in this guide." +msgstr "Het installeren duurt naar verwachting zo'n *half uur* (op een RaspberryPi 2/3), maar hangt natuurlijk ook af van je eigen vaardigheid op de command line." #: ../../installation.rst:14 msgid "Dependencies & requirements" @@ -38,764 +19,460 @@ msgstr "Afhankelijkheden & vereisten" msgid "**RaspberryPi 2 or 3**" msgstr "**RaspberryPi 2 of 3**" -#: ../../installation.rst:17 -msgid "" -"The RaspberryPi 1 tends to be **too slow** for this project, as it requires " -"multi core processing." -msgstr "" -"De RaspberryPi 1 lijkt **te traag** voor het draaien van dit project, gezien " -"meerdere processoren vrijwel vereist zijn." +#: ../../installation.rst:19 +msgid "**Alternative #1**: You can also run it on any server near your smart meter, as long as it satisfies the other requirements." +msgstr "**Alternatief #1**: Je kunt dit natuurlijk ook draaien op een server vlakbij je slimme meter, zolang de vereisten maar ondersteund worden." #: ../../installation.rst:21 -msgid "" -"**Alternative #1**: You can also run it on any server near your smart meter, as " -"long as it satisfies the other requirements." -msgstr "" -"**Alternatief #1**: Je kunt dit natuurlijk ook draaien op een server vlakbij je " -"slimme meter, zolang de vereisten maar ondersteund worden." - -#: ../../installation.rst:23 -msgid "" -"**Alternative #2**: The application supports receiving P1 telegrams using an " -"API, so you can also run it on a server outside your home. (:doc:`API " -"DOCS`)" -msgstr "" -"**Alternatief #2**: De applicatie ondersteunt het ontvangen van P1 telegrammen " -"via een API, dus je kunt dit ook op een server buiten je huis draaien. (:doc:" -"`API DOCS`)" +msgid "**Alternative #2**: The application supports receiving P1 telegrams using an API, so you can also run it on a server outside your home. (:doc:`API DOCS`)" +msgstr "**Alternatief #2**: De applicatie ondersteunt het ontvangen van P1 telegrammen via een API, dus je kunt dit ook op een server buiten je huis draaien. (:doc:`API DOCS`)" #: ../../installation.rst:25 -msgid "**Raspbian OS**" -msgstr "**Raspbian OS**" +msgid "The RaspberryPi 1 tends to be **too slow** for this project, as it requires multi core processing." +msgstr "De RaspberryPi 1 lijkt **te traag** voor het draaien van dit project, gezien meerdere processoren vrijwel vereist zijn." #: ../../installation.rst:27 -msgid "" -"Recommended and tested with, but any OS satisfying the requirements should do " -"fine." -msgstr "" -"Aanbevolen en mee getest, al zou elk OS die dezelfde vereisten ondersteunt " -"prima moeten zijn." +msgid "You can however run just the datalogger client on an old RaspberryPi, :doc:`see for the API for a howto and example scripts`." +msgstr "Je kunt echter wel alleen een datalogger client draaien op een oude RaspberryPi, :doc:`zie de API -documentatie voor meer informatie en voorbeeldscripts`." #: ../../installation.rst:29 -msgid "**Python 3.4+**" -msgstr "**Python 3.4+**" +msgid "**Raspbian OS**" +msgstr "**Raspbian OS**" -#: ../../installation.rst:33 -msgid "" -"Support for ``Python 3.3`` has been **discontinued** since ``DSMR-reader v1.5`` " -"(due to Django)." -msgstr "" -"Ondersteuning voor ``Python 3.3`` is **vervallen** sinds ``DSMR-reader v1.5`` " -"(vanwege Django)." +#: ../../installation.rst:31 +msgid "Recommended and tested with, but any OS satisfying the requirements should do fine." +msgstr "Aanbevolen en mee getest, al zou elk OS die dezelfde vereisten ondersteunt prima moeten zijn." -#: ../../installation.rst:35 -msgid "**PostgreSQL 9+ or MySQL / MariaDB 5.5+**" -msgstr "**PostgreSQL 9+ of MySQL / MariaDB 5.5+**" +#: ../../installation.rst:33 +msgid "**Python 3.4+**" +msgstr "**Python 3.4+**" #: ../../installation.rst:37 -msgid "" -"I **highly recommend** ``PostgreSQL`` due to builtin support for timezones." -msgstr "" -"Ik raad ``PostgreSQL`` **sterk** aan wegens de goede ingebouwde ondersteuning " -"voor tijdzones." +msgid "Support for ``Python 3.3`` has been **discontinued** since ``DSMR-reader v1.5`` (due to Django)." +msgstr "Ondersteuning voor ``Python 3.3`` is **vervallen** sinds ``DSMR-reader v1.5`` (vanwege Django)." #: ../../installation.rst:39 -msgid "" -"**Smart Meter** with support for **at least DSMR 4.x+** and a **P1 telegram " -"port**" -msgstr "" -"**Slimme meter** met ondersteuning voor **ten minste DSMR 4.x+** en een **P1 " -"telegram poort**" - -#: ../../installation.rst:41 -msgid "" -"Tested so far with Landis+Gyr E350, Kaifa. Telegram port looks like an RJ11 " -"(phone) socket." -msgstr "" -"Tot nu toe getest met Landis+Gyr E350, Kaifa. Telegram poort (P1) ziet er uit " -"als een RJ11 (telefoon) aansluiting." +msgid "**PostgreSQL 9+ database**" +msgstr "**PostgreSQL 9+ database**" #: ../../installation.rst:43 -msgid "" -"**Minimal 1 GB of disk space on RaspberryPi (card)** (for application " -"installation & virtualenv)." -msgstr "" -"**Minimaal 1 GB schijfruimte vereist op RaspberryPi (SD-kaart)** (ten behoeve " -"van de applicatie en VirtualEnv)." - -#: ../../installation.rst:45 -msgid "" -"More disk space is required for storing all reader data captured (optional). I " -"generally advise to use a 8+ GB SD card." -msgstr "" -"Meer schijfruimte is nodig voor het opslaan van alle metingen (optioneel). Over " -"het algemeen adviseer ik minimaal een 8 GB SD-kaart." +msgid "Support for ``MySQL`` has been **deprecated** since ``DSMR-reader v1.6`` and will be discontinued completely in a later release. Please use a PostgreSQL database instead. Users already running MySQL will be supported in migrating at a later moment." +msgstr "Gebruik van ``MySQL`` wordt **afgeraden** sinds ``DSMR-reader v1.6`` en ondersteuning hiervoor verdwijnt helemaal in een toekomstige versie. Gebruik daarom PostgreSQL. Gebruikers die dit project al op MySQL draaien krijgen in de toekomst ondersteuning om te migreren." #: ../../installation.rst:46 -msgid "" -"The readings will take about 90+ percent of the disk space. Retention is on " -"it's way for a future release in 2017." -msgstr "" -"De metingen nemen zo'n 90+ procent van alle schijfruimte in beslag. Er komt " -"echter een optie voor retentie in een toekomstige release in 2017." +msgid "**Smart Meter** with support for **at least DSMR 4.x+** and a **P1 telegram port**" +msgstr "**Slimme meter** met ondersteuning voor **ten minste DSMR 4.x+** en een **P1 telegram poort**" #: ../../installation.rst:48 +msgid "Tested so far with Landis+Gyr E350, Kaifa." +msgstr "Tot nu toe getest met: Landis+Gyr E350, Kaifa." + +#: ../../installation.rst:50 +msgid "**Minimal 1 GB of disk space on RaspberryPi (card)** (for application installation & virtualenv)." +msgstr "**Minimaal 1 GB schijfruimte vereist op RaspberryPi (SD-kaart)** (ten behoeve van de applicatie en VirtualEnv)." + +#: ../../installation.rst:52 +msgid "More disk space is required for storing all reader data captured (optional). I generally advise to use a 8+ GB SD card." +msgstr "Meer schijfruimte is nodig voor het opslaan van alle metingen (optioneel). Over het algemeen adviseer ik minimaal een 8 GB SD-kaart." + +#: ../../installation.rst:53 +msgid "The readings will take about 90+ percent of the disk space. Retention is on it's way for a future release in 2017." +msgstr "De metingen nemen zo'n 90+ procent van alle schijfruimte in beslag. Er komt echter een optie voor retentie in een toekomstige release in 2017." + +#: ../../installation.rst:55 msgid "**Smart meter P1 data cable**" msgstr "**Slimme meter P1 data kabel**" -#: ../../installation.rst:50 +#: ../../installation.rst:57 msgid "Can be purchased online and they cost around 15 tot 20 Euro's each." msgstr "Je kunt deze online bestellen voor ongeveer 15 a 20 Euro." -#: ../../installation.rst:52 +#: ../../installation.rst:59 msgid "**Basic Linux knowledge for deployment, debugging and troubleshooting**" -msgstr "" -"**Basiskennis Linux voor het uitrollen en mogelijk debuggen van problemen**" +msgstr "**Basiskennis Linux voor het uitrollen en mogelijk debuggen van problemen**" -#: ../../installation.rst:54 +#: ../../installation.rst:61 msgid "It just really helps if you know what you are doing." msgstr "Het scheelt eenmaal een hoop wanneer je weet waar je mee bezig bent." -#: ../../installation.rst:58 -msgid "1. Database backend" -msgstr "1. Databaseopslag" - -#: ../../installation.rst:60 -msgid "" -"The application stores by default all readings taken from the serial cable. " -"Depending on your needs, you can choose for either (Option A.) **PostgreSQL** " -"(Option B.) **MySQL/MariaDB**." -msgstr "" -"De applicatie slaat alle metingen op in een database. Afhankelijk van je wensen " -"en behoeftes heb je de keuze uit: (Keuze A.) **PostgreSQL** (Keuze B.) **MySQL/" -"MariaDB**." - -#: ../../installation.rst:64 -msgid "" -"If you have no idea what to choose, I generally advise to pick PostgreSQL, as " -"it has builtin support for (local) timezone handling (required for daylight " -"saving time transitions)." -msgstr "" -"Wanneer je geen idee hebt wat je moet kiezen, dan adviseer ik doorgaans om " -"PostgreSQL te kiezen. Dit vanwege de uitstekende ingebouwde ondersteuning voor " -"tijdzones (nodig voor zomer-/wintertijd)." - -#: ../../installation.rst:67 ../../installation.rst:269 -msgid "(Option A.) PostgreSQL" -msgstr "(Keuze A.) PostgreSQL" - -#: ../../installation.rst:68 -msgid "" -"Install PostgreSQL, ``postgresql-server-dev-all`` is required for the " -"virtualenv installation later in this guide." -msgstr "" -"Installeer PostgreSQL. Daarnaast is ``postgresql-server-dev-all`` nodig voor " -"het installeren van de VirtualEnv later." - -#: ../../installation.rst:70 ../../installation.rst:107 +#: ../../installation.rst:65 +msgid "1. Database backend (PostgreSQL)" +msgstr "1. Databaseopslag (PostgreSQL)" + +#: ../../installation.rst:67 +msgid "The application stores by default all readings taken from the serial cable. There is support for **PostgreSQL**, and there used to be support for **MySQL/MariaDB** as well. The latter is currently deprecated by this project and support will be discontinued in a future release." +msgstr "De applicatie slaat de P1-metingen standaard op. Er is ondersteuning voor **PostgreSQL**, en vroeger ook voor **MySQL/MariaDB**. Alleen wordt de laatstgenoemde momenteel afgeraden om te gebruiken (ondersteuning vervalt later)." + +#: ../../installation.rst:71 +msgid "Install PostgreSQL, ``postgresql-server-dev-all`` is required for the virtualenv installation later in this guide." +msgstr "Installeer PostgreSQL. Daarnaast is ``postgresql-server-dev-all`` nodig voor het installeren van de VirtualEnv later." + +#: ../../installation.rst:73 ../../installation.rst:118 msgid "Install database::" msgstr "Installeer database::" -#: ../../installation.rst:74 -msgid "" -"Does Postgres not start due to locales? Try: ``dpkg-reconfigure locales``. " -"Still no luck? Try editing ``/etc/environment``, add ``LC_ALL=\"en_US.utf-8\"`` " -"and reboot." -msgstr "" -"Start PostgreSQL niet wegens een fout in 'locales'? Probeer dan het volgende: " -"``dpkg-reconfigure locales``. Werkt het nog steeds niet? Open dan dit bestand " -"``/etc/environment``, voeg onderaan de regel ``LC_ALL=\"en_US.utf-8\"`` toe en " -"herstart het systeem." - -#: ../../installation.rst:76 -msgid "" -"(!) Ignore any '*could not change directory to \"/root\": Permission denied*' " -"errors for the following three commands." -msgstr "" -"(!) Negeer voor de volgende drie commando's de foutmelding: '*could not change " -"directory to \"/root\": Permission denied*'." - -#: ../../installation.rst:78 ../../installation.rst:115 +#: ../../installation.rst:77 +msgid "Does Postgres not start due to locales? Try: ``dpkg-reconfigure locales``. Still no luck? Try editing ``/etc/environment``, add ``LC_ALL=\"en_US.utf-8\"`` and reboot." +msgstr "Start PostgreSQL niet wegens een fout in 'locales'? Probeer dan het volgende: ``dpkg-reconfigure locales``. Werkt het nog steeds niet? Open dan dit bestand ``/etc/environment``, voeg onderaan de regel ``LC_ALL=\"en_US.utf-8\"`` toe en herstart het systeem." + +#: ../../installation.rst:80 +msgid "(!) Ignore any '*could not change directory to \"/root\": Permission denied*' errors for the following three commands." +msgstr "(!) Negeer voor de volgende drie commando's de foutmelding: '*could not change directory to \"/root\": Permission denied*'." + +#: ../../installation.rst:82 ../../installation.rst:126 msgid "Create database user::" msgstr "Creëer databasegebruiker::" -#: ../../installation.rst:82 +#: ../../installation.rst:86 msgid "Create database, owned by the database user we just created::" -msgstr "" -"Creëer database, met als eigenaar de databasegebruiker die we net hebben " -"aangemaakt::" +msgstr "Creëer database, met als eigenaar de databasegebruiker die we net hebben aangemaakt::" -#: ../../installation.rst:86 +#: ../../installation.rst:90 msgid "Set password for database user::" msgstr "Stel wachtwoord in voor databasegebruiker::" -#: ../../installation.rst:92 -msgid "" -"**Optional**: Do you need to restore a **PostgreSQL** database backup as well?" -msgstr "" -"**Optioneel**: Wil je ook nog een **PostgreSQL** database back-up herstellen?" +#: ../../installation.rst:96 +msgid "**Optional**: Do you need to restore a **PostgreSQL** database backup as well?" +msgstr "**Optioneel**: Wil je ook nog een **PostgreSQL** database back-up herstellen?" -#: ../../installation.rst:94 ../../installation.rst:131 +#: ../../installation.rst:98 ../../installation.rst:142 msgid "Restore an uncompressed (``.sql``) backup with::" msgstr "Herstel een ongecomprimeerde (``.sql``) back-up met::" -#: ../../installation.rst:98 ../../installation.rst:135 +#: ../../installation.rst:102 ../../installation.rst:146 msgid "Or restore a compressed (``.gz``) backup with::" msgstr "Of herstel een gecomprimeerde (``.gz``) back-up met::" -#: ../../installation.rst:104 ../../installation.rst:277 -msgid "(Option B.) MySQL/MariaDB" -msgstr "(Keuze B.) MySQL/MariaDB" - -#: ../../installation.rst:105 -msgid "" -"Install MariaDB. You can also choose to install the closed source MySQL, as " -"they should be interchangeable anyway. ``libmysqlclient-dev`` is required for " -"the virtualenv installation later in this guide." -msgstr "" -"Installeer MariaDB. Je kunt er ook voor kiezen om het closed-source MySQL te " -"installeren. Welke je ook kiest, ``libmysqlclient-dev`` is later nodig voor de " -"VirtualEnv." - -#: ../../installation.rst:111 +#: ../../installation.rst:106 +msgid "Now continue at chapter 2 below (Dependencies)." +msgstr "Ga door naar hoofdstuk 2 verderop (Dependencies)." + +#: ../../installation.rst:109 ../../installation.rst:294 +msgid "(Legacy) MySQL/MariaDB" +msgstr "(Legacy) MySQL/MariaDB" + +#: ../../installation.rst:112 ../../installation.rst:297 +msgid "Support for the MySQL database backend is deprecated and will be removed in a later release. Please use a PostgreSQL database instead. Users already running MySQL will be supported in migrating at a later moment." +msgstr "Gebruik van MySQL-databases wordt afgeraden en de ondersteuning hiervoor stopt in een latere release. Gebruik daarom PostgreSQL. Gebruikers die dit project al op MySQL draaien krijgen in de toekomst ondersteuning om te migreren." + +#: ../../installation.rst:115 +msgid "Install MariaDB. You can also choose to install the closed source MySQL, as they should be interchangeable anyway. ``libmysqlclient-dev`` is required for the virtualenv installation later in this guide." +msgstr "Installeer MariaDB. Je kunt er ook voor kiezen om het closed-source MySQL te installeren. Welke je ook kiest, ``libmysqlclient-dev`` is later nodig voor de VirtualEnv." + +#: ../../installation.rst:122 msgid "Create database::" msgstr "Creëer database::" -#: ../../installation.rst:119 +#: ../../installation.rst:130 msgid "Set privileges for database user::" msgstr "Stel rechten in voor databasegebruiker::" -#: ../../installation.rst:123 +#: ../../installation.rst:134 msgid "Flush privileges to activate them::" msgstr "Pas de databaserechten toe::" -#: ../../installation.rst:129 +#: ../../installation.rst:140 msgid "**Optional**: Do you need to restore a **MySQL** database backup as well?" msgstr "**Optioneel**: Wil je ook nog een **MySQL** database back-up herstellen?" -#: ../../installation.rst:141 +#: ../../installation.rst:152 msgid "2. Dependencies" msgstr "2. Afhankelijkheden" -#: ../../installation.rst:142 -msgid "" -"Now you'll have to install several utilities, required for the Nginx webserver, " -"Gunicorn application server and cloning the application code from the Github " -"repository::" -msgstr "" -"Tijd om diverse tools te installeren. Deze zijn nodig voor de Nginx webserver, " -"de Gunicorn applicatieserver en voor het binnenhalen van de code van de " -"applicatie vanaf Github::" - -#: ../../installation.rst:146 -msgid "" -"Install ``cu``. The CU program allows easy testing for your DSMR serial " -"connection. It's very basic but also very effective to simply test whether your " -"serial cable setup works properly. ::" -msgstr "" -"Installeer ``cu``. Met dit programmaatje kunnen we vrij gemakkelijk de DSMR-" -"verbinding testen naar je slimme meter toe. Erg handig om te kijken of dat " -"überhaupt al lekker werkt." +#: ../../installation.rst:153 +msgid "Now you'll have to install several utilities, required for the Nginx webserver, Gunicorn application server and cloning the application code from the Github repository::" +msgstr "Tijd om diverse tools te installeren. Deze zijn nodig voor de Nginx webserver, de Gunicorn applicatieserver en voor het binnenhalen van de code van de applicatie vanaf Github::" -#: ../../installation.rst:152 +#: ../../installation.rst:157 +msgid "Install ``cu``. The CU program allows easy testing for your DSMR serial connection. It's very basic but also very effective to simply test whether your serial cable setup works properly::" +msgstr "Installeer ``cu``. Met dit programmaatje kunnen kun je vrij gemakkelijk de DSMR-verbinding testen naar je slimme meter toe. Erg handig om te kijken of dat überhaupt al lekker werkt::" + +#: ../../installation.rst:164 msgid "3. Application user" msgstr "3. Applicatiegebruiker" -#: ../../installation.rst:153 -msgid "" -"The application runs as ``dsmr`` user by default. This way we do not have to " -"run the application as ``root``, which is a bad practice anyway." -msgstr "" -"De applicatie draait standaard onder de gebruiker ``dsmr``. Hierdoor heeft het " -"geen ``root``-rechten (nodig), wat over het algemeen zeer afgeraden wordt." - -#: ../../installation.rst:155 -msgid "" -"Create user with homedir. The application code and virtualenv will reside in " -"this directory as well::" -msgstr "" -"Maak een aparte gebruiker aan met eigen homedir. De code voor de applicatie en " -"VirtualEnv zetten we later hier in::" - -#: ../../installation.rst:159 -msgid "" -"Our user also requires dialout permissions. So allow the user to perform a " -"dialout by adding it to the ``dialout`` group::" -msgstr "" -"De gebruiker heeft ook toegang nodig om de kabel te kunnen uitlezen. Hiervoor " -"voegen de we gebruiker toe aan de groep ``dialout``::" - -#: ../../installation.rst:163 -msgid "" -"Either proceed to the next heading **for a test reading** or continue at " -"chapter 4." -msgstr "" -"Ga ofwel door naar het volgende hoofdstuk **voor een testmeting** of ga direct " -"door naar stap 4." +#: ../../installation.rst:165 +msgid "The application runs as ``dsmr`` user by default. This way we do not have to run the application as ``root``, which is a bad practice anyway." +msgstr "De applicatie draait standaard onder de gebruiker ``dsmr``. Hierdoor heeft het geen ``root``-rechten (nodig), wat over het algemeen zeer afgeraden wordt." #: ../../installation.rst:167 +msgid "Create user with homedir. The application code and virtualenv will reside in this directory as well::" +msgstr "Maak een aparte gebruiker aan met eigen homedir. De code voor de applicatie en VirtualEnv zetten we later hier in::" + +#: ../../installation.rst:171 +msgid "Our user also requires dialout permissions. So allow the user to perform a dialout by adding it to the ``dialout`` group::" +msgstr "De gebruiker heeft ook toegang nodig om de kabel te kunnen uitlezen. Hiervoor voegen de we gebruiker toe aan de groep ``dialout``::" + +#: ../../installation.rst:175 +msgid "Either proceed to the next heading **for a test reading** or continue at chapter 4." +msgstr "Ga ofwel door naar het volgende hoofdstuk **voor een testmeting** of ga direct door naar stap 4." + +#: ../../installation.rst:179 msgid "Your first reading (optional)" msgstr "Je allereerste (optionele) meting" -#: ../../installation.rst:171 -msgid "" -"**OPTIONAL**: You may skip this section as it's not required for the " -"application to install. However, if you have never read your meter's P1 " -"telegram port before, I recommend to perform an initial reading to make sure " -"everything works as expected." -msgstr "" -"**OPTIONEEL**: Je kunt deze stap overslaan wanneer je al eerder een " -"(test)meting hebt gedaan met je slimme meter. Ik raad het dus vooral aan als je " -"nog nooit eerder je P1-poort hebt uitgelezen. Hiermee verzeker je jezelf ook " -"dat de applicatie straks dezelfde (werkende) toegang heeft voor de metingen." - -#: ../../installation.rst:173 -msgid "" -"Now login as the user we have just created, to perform our very first " -"reading! ::" -msgstr "" -"Log nu in als de gebruiker die we zojuist hebben aangemaakt voor de eerste " -"testmeting! ::" - -#: ../../installation.rst:177 +#: ../../installation.rst:183 +msgid "**OPTIONAL**: You may skip this section as it's not required for the application to install. However, if you have never read your meter's P1 telegram port before, I recommend to perform an initial reading to make sure everything works as expected." +msgstr "**OPTIONEEL**: Je kunt deze stap overslaan wanneer je al eerder een (test)meting hebt gedaan met je slimme meter. Ik raad het dus vooral aan als je nog nooit eerder je P1-poort hebt uitgelezen. Hiermee verzeker je jezelf ook dat de applicatie straks dezelfde (werkende) toegang heeft voor de metingen." + +#: ../../installation.rst:185 +msgid "Now login as the user we have just created, to perform our very first reading! ::" +msgstr "Log nu in als de gebruiker die we zojuist hebben aangemaakt voor de eerste testmeting! ::" + +#: ../../installation.rst:189 msgid "Test with ``cu`` for **DSMR 4+**::" msgstr "Test met ``cu`` voor **DSMR 4+**::" -#: ../../installation.rst:181 +#: ../../installation.rst:193 msgid "Or test with ``cu`` for **DSMR 2.2** (untested)::" msgstr "Of test met ``cu`` voor **DSMR 2.2** (ongetest)::" -#: ../../installation.rst:185 -msgid "" -"You now should see something similar to ``Connected.`` and a wall of text and " -"numbers *within 10 seconds*. Nothing? Try different BAUD rate, as mentioned " -"above. You might also check out a useful blog, `such as this one (Dutch) " -"`_." -msgstr "" -"Je zou nu iets moeten zien als ``Connected.``. Vervolgens krijg je, als het " -"goed is, binnen tien seconden een hele lap tekst te zijn met een hoop cijfers. " -"Werkt het niet? Probeer dan een andere BAUD-waarde, zoals hierboven beschreven. " -"Of `kijk op een nuttig weblog `_." - -#: ../../installation.rst:187 -msgid "" -"To exit cu, type \"``q.``\", hit Enter and wait for a few seconds. It should " -"exit with the message ``Disconnected.``." -msgstr "" -"Om cu af te sluiten, typ \"``q.``\", druk op Enter en wacht voor een paar " -"seconden. Het programma sluit af met de melding ``Disconnected.``." - -#: ../../installation.rst:191 +#: ../../installation.rst:197 +msgid "You now should see something similar to ``Connected.`` and a wall of text and numbers *within 10 seconds*. Nothing? Try different BAUD rate, as mentioned above. You might also check out a useful blog, `such as this one (Dutch) `_." +msgstr "Je zou nu iets moeten zien als ``Connected.``. Vervolgens krijg je, als het goed is, binnen tien seconden een hele lap tekst te zijn met een hoop cijfers. Werkt het niet? Probeer dan een andere BAUD-waarde, zoals hierboven beschreven. Of `kijk op een nuttig weblog `_." + +#: ../../installation.rst:199 +msgid "To exit cu, type \"``q.``\", hit Enter and wait for a few seconds. It should exit with the message ``Disconnected.``." +msgstr "Om cu af te sluiten, typ \"``q.``\", druk op Enter en wacht voor een paar seconden. Het programma sluit af met de melding ``Disconnected.``." + +#: ../../installation.rst:203 msgid "4. Webserver/Nginx (part 1)" msgstr "4. Webserver/Nginx (deel 1)" -#: ../../installation.rst:193 -msgid "" -"*We will now prepare the webserver, Nginx. It will serve all application's " -"static files directly and proxy any application requests to the backend, " -"Gunicorn controlled by Supervisor, which we will configure later on.*" -msgstr "" -"*We configureren vervolgens de webserver (Nginx). Deze serveert alle statische " -"bestanden en geeft de applicatie-verzoeken door naar de backend, waar de " -"applicatie in Gunicorn draait onder Supervisor. Deze stellen we later in.*" - -#: ../../installation.rst:195 +#: ../../installation.rst:205 +msgid "*We will now prepare the webserver, Nginx. It will serve all application's static files directly and proxy any application requests to the backend, Gunicorn controlled by Supervisor, which we will configure later on.*" +msgstr "*We configureren vervolgens de webserver (Nginx). Deze serveert alle statische bestanden en geeft de applicatie-verzoeken door naar de backend, waar de applicatie in Gunicorn draait onder Supervisor. Deze stellen we later in.*" + +#: ../../installation.rst:207 msgid "Make sure you are still acting here as ``root`` or ``sudo`` user." msgstr "Zorg ervoor dat je hier nog steeds ``root``- of ``sudo``-gebruiker bent." -#: ../../installation.rst:197 -msgid "" -"Django will later copy all static files to the directory below, used by Nginx " -"to serve statics. Therefor it requires (write) access to it::" -msgstr "" -"Django kopieert alle statische bestanden naar een aparte map, die weer door " -"Nginx gebruikt wordt. Daarom is er tevens (schrijf)toegang voor nodig::" +#: ../../installation.rst:209 +msgid "Django will later copy all static files to the directory below, used by Nginx to serve statics. Therefor it requires (write) access to it::" +msgstr "Django kopieert alle statische bestanden naar een aparte map, die weer door Nginx gebruikt wordt. Daarom is er tevens (schrijf)toegang voor nodig::" -#: ../../installation.rst:205 +#: ../../installation.rst:217 msgid "5. Clone project code from Github" msgstr "5. Kloon project code vanaf Github" -#: ../../installation.rst:206 -msgid "" -"Now is the time to clone the code from the repository into the homedir we " -"created." -msgstr "" -"Nu kunnen we de code van de applicatie van Github downloaden en in de homedir " -"zetten die we net aangemaakt hebben." - -#: ../../installation.rst:208 -msgid "" -"Make sure you are now acting as ``dsmr`` user (if not then enter: ``sudo su - " -"dsmr``)" -msgstr "" -"Zorg ervoor dat je ingelogd bent als ``dsmr``-gebruiker (zo niet, typ dan: " -"``sudo su - dsmr``)" - -#: ../../installation.rst:210 +#: ../../installation.rst:218 +msgid "Now is the time to clone the code from the repository into the homedir we created." +msgstr "Nu kunnen we de code van de applicatie van Github downloaden en in de homedir zetten die we net aangemaakt hebben." + +#: ../../installation.rst:220 +msgid "Make sure you are now acting as ``dsmr`` user (if not then enter: ``sudo su - dsmr``)" +msgstr "Zorg ervoor dat je ingelogd bent als ``dsmr``-gebruiker (zo niet, typ dan: ``sudo su - dsmr``)" + +#: ../../installation.rst:222 msgid "Clone the repository::" msgstr "Kloon de repository::" -#: ../../installation.rst:214 -msgid "" -"This may take a few seconds. When finished, you should see a new folder called " -"``dsmr-reader``, containing a clone of the Github repository." -msgstr "" -"Dit kan enkele seconden in beslag nemen. Als het goed is zie je hierna een map " -"genaamd ``dsmr-reader``, met daarin een kopie van de repository zoals die op " -"Github staat." +#: ../../installation.rst:226 +msgid "This may take a few seconds. When finished, you should see a new folder called ``dsmr-reader``, containing a clone of the Github repository." +msgstr "Dit kan enkele seconden in beslag nemen. Als het goed is zie je hierna een map genaamd ``dsmr-reader``, met daarin een kopie van de repository zoals die op Github staat." -#: ../../installation.rst:218 +#: ../../installation.rst:230 msgid "6. Virtualenv" msgstr "6. VirtualEnv" -#: ../../installation.rst:220 -msgid "" -"The dependencies our application uses are stored in a separate environment, " -"also called **VirtualEnv**." -msgstr "" -"Alle (externe) afhankelijkheden worden opgeslagen in een aparte omgeving, ook " -"wel **VirtualEnv** genoemd." +#: ../../installation.rst:232 +msgid "The dependencies our application uses are stored in a separate environment, also called **VirtualEnv**." +msgstr "Alle (externe) afhankelijkheden worden opgeslagen in een aparte omgeving, ook wel **VirtualEnv** genoemd." -#: ../../installation.rst:222 -msgid "" -"Although it's just a folder inside our user's homedir, it's very effective as " -"it allows us to keep dependencies isolated or to run different versions of the " -"same package on the same machine. `More information about this subject can be " -"found here `_." -msgstr "" -"Dit is allemaal erg handig, ondanks dat het feitelijk niets meer voorstelt dan " -"een aparte map binnen de homedir van onze gebruiker. Hierdoor kunnen we " -"namelijk meerdere versie van software op hetzelfde systeem installeren, zonder " -"dat dat elkaar bijt. Meer informatie hierover `kan hier gevonden worden `_." - -#: ../../installation.rst:225 -msgid "" -"Make sure you are still acting as ``dsmr`` user (if not then enter: ``sudo su - " -"dsmr``)" -msgstr "" -"Zorg ervoor dat je nog steeds ingelogd bent als ``dsmr``-gebruiker (zo niet, " -"typ dan: ``sudo su - dsmr``)" - -#: ../../installation.rst:227 -msgid "Create folder for the virtualenv(s) of this user::" -msgstr "Maak map aan voor de VirtualEnv van deze gebruiker::" - -#: ../../installation.rst:231 -msgid "" -"Create a new virtualenv, we usually use the same name for it as the application " -"or project::" -msgstr "" -"Maak een nieuwe VirtualEnv aan. Het is gebruikelijk om hiervoor dezelfde naam " -"te gebruiken als die van de applicatie of het project." +#: ../../installation.rst:234 +msgid "Although it's just a folder inside our user's homedir, it's very effective as it allows us to keep dependencies isolated or to run different versions of the same package on the same machine. `More information about this subject can be found here `_." +msgstr "Dit is allemaal erg handig, ondanks dat het feitelijk niets meer voorstelt dan een aparte map binnen de homedir van onze gebruiker. Hierdoor kunnen we namelijk meerdere versie van software op hetzelfde systeem installeren, zonder dat dat elkaar bijt. Meer informatie hierover `kan hier gevonden worden `_." #: ../../installation.rst:237 -msgid "" -"Note that it's important to specify **Python 3** as the default interpreter." -msgstr "" -"N.B.: het is belangrijk dat je voor deze VirtualEnv aangeeft dat **Python 3** " -"de gewenste standaardversie is::" +msgid "Make sure you are still acting as ``dsmr`` user (if not then enter: ``sudo su - dsmr``)" +msgstr "Zorg ervoor dat je nog steeds ingelogd bent als ``dsmr``-gebruiker (zo niet, typ dan: ``sudo su - dsmr``)" #: ../../installation.rst:239 -msgid "" -"Put both commands below in the ``dsmr`` user's ``~/.bashrc`` file with your " -"favorite text editor::" -msgstr "" -"Zet beide commands in het ``~/.bashrc`` bestand van de ``dsmr`` gebruiker met " -"je favoriete bestandseditor::" - -#: ../../installation.rst:245 -msgid "" -"This will both **activate** the virtual environment and cd you into the right " -"directory on your **next login** as ``dsmr`` user." -msgstr "" -"Hiermee wordt zowel de VirtualEnv geactiveerd én ga je direct naar de juiste " -"map. Dit werkt de **eerstvolgende keer** dat je inlogt als ``dsmr`` gebruiker." +msgid "Create folder for the virtualenv(s) of this user::" +msgstr "Maak map aan voor de VirtualEnv van deze gebruiker::" + +#: ../../installation.rst:243 +msgid "Create a new virtualenv, we usually use the same name for it as the application or project::" +msgstr "Maak een nieuwe VirtualEnv aan. Het is gebruikelijk om hiervoor dezelfde naam te gebruiken als die van de applicatie of het project." #: ../../installation.rst:249 -msgid "" -"You can easily test whether you've configured this correctly by logging out the " -"``dsmr`` user (CTRL + D) and login again using ``sudo su - dsmr``." -msgstr "" -"Je kunt dit vrij gemakkelijk testen door uit te loggen als ``dsmr`` gebruiker " -"(met CTRL + D) en vervolgens weer in te loggen met ``sudo su - dsmr``." +msgid "Note that it's important to specify **Python 3** as the default interpreter." +msgstr "N.B.: het is belangrijk dat je voor deze VirtualEnv aangeeft dat **Python 3** de gewenste standaardversie is::" #: ../../installation.rst:251 -msgid "" -"You should see the terminal have a ``(dsmrreader)`` prefix now, for example: " -"``(dsmrreader)dsmr@rasp:~/dsmr-reader $``" -msgstr "" -"Als het goed is heeft je terminal nu een ``(dsmrreader)`` prefix, bijvoorbeeld: " -"``(dsmrreader)dsmr@rasp:~/dsmr-reader $``" - -#: ../../installation.rst:253 -msgid "" -"Make sure you've read and executed the note above, because you'll need it for " -"the next chapter." -msgstr "" -"Zorg ervoor dat je bovenstaande notities hebt gelezen én uitgevoerd, aangezien " -"ze nodig zijn voor het volgende hoofdstuk." +msgid "Put both commands below in the ``dsmr`` user's ``~/.bashrc`` file with your favorite text editor::" +msgstr "Zet beide commands in het ``~/.bashrc`` bestand van de ``dsmr`` gebruiker met je favoriete bestandseditor::" #: ../../installation.rst:257 +msgid "This will both **activate** the virtual environment and cd you into the right directory on your **next login** as ``dsmr`` user." +msgstr "Hiermee wordt zowel de VirtualEnv geactiveerd en ga je direct naar de juiste map. Dit werkt de **eerstvolgende keer** dat je inlogt als ``dsmr`` gebruiker." + +#: ../../installation.rst:261 +msgid "You can easily test whether you've configured this correctly by logging out the ``dsmr`` user (CTRL + D) and login again using ``sudo su - dsmr``." +msgstr "Je kunt dit vrij gemakkelijk testen door uit te loggen als ``dsmr`` gebruiker (met CTRL + D) en vervolgens weer in te loggen met ``sudo su - dsmr``." + +#: ../../installation.rst:263 +msgid "You should see the terminal have a ``(dsmrreader)`` prefix now, for example: ``(dsmrreader)dsmr@rasp:~/dsmr-reader $``" +msgstr "Als het goed is heeft je terminal nu een ``(dsmrreader)`` prefix, bijvoorbeeld: ``(dsmrreader)dsmr@rasp:~/dsmr-reader $``" + +#: ../../installation.rst:265 +msgid "Make sure you've read and executed the note above, because you'll need it for the next chapter." +msgstr "Zorg ervoor dat je de bovenstaande notitie hebt gelezen en uitgevoerd, aangezien ze nodig zijn voor het volgende hoofdstuk." + +#: ../../installation.rst:269 msgid "7. Application configuration & setup" msgstr "7. Applicatieconfiguratie" -#: ../../installation.rst:258 -msgid "" -"Earlier in this guide you had to choose for either **(A.) PostgreSQL** or " -"**(B.) MySQL/MariaDB**. Our application needs to know which backend used in " -"order to communicate with it." -msgstr "" -"Eerder tijdens de installatie moest je kiezen voor ofwel **(A.) PostgreSQL** " -"ofwel **(B.) MySQL/MariaDB**. De applicatie moet zelf ook weten met welke " -"variant hij communiceert." - -#: ../../installation.rst:260 -msgid "" -"Therefor I created two default (Django-)settings files you can copy, one for " -"each backend. The application will also need the appropriate database client, " -"which is not installed by default. For this I also created two ready-to-use " -"requirements files, which will also install all other dependencies required, " -"such as the Django framework." -msgstr "" -"Daarom heb ik twee standaard (Django-)configuraties gemaakt die je gewoon kan " -"kopiëren. Daarnaast heeft elke database zijn eigen database-client nodig. " -"Daarvoor heb ik ook een tweetal requirements-bestanden gemaakt, waar alles al " -"in staat wat nodig is. Zoals bijvoorbeeld Django en de databaseverbinding." - -#: ../../installation.rst:262 -msgid "" -"The ``base.txt`` contains requirements which the application needs anyway, no " -"matter which backend you've choosen." -msgstr "" -"Het bestand ``base.txt`` bevat alle afhankelijkheden die de applicatie sowieso " -"nodig heeft, ongeacht de databasekeuze die je gemaakt hebt." - -#: ../../installation.rst:266 -msgid "" -"**Installation of the requirements below might take a while**, depending on " -"your Internet connection, RaspberryPi speed and resources (generally CPU) " -"available. Nothing to worry about. :]" -msgstr "" -"**De installatie van de volgende afhankelijkheden kan enige tijd in beslag " -"nemen**. Dit varieert en is sterk afhankelijk van de snelheid van je Internet-" -"verbinding en je RaspberryPi. Je hoeft je dus niet zorgen te maken wanneer dit " -"lang lijkt te duren. :]" - #: ../../installation.rst:270 +msgid "The application will also need the appropriate database client, which is not installed by default. For this I created two ready-to-use requirements files, which will also install all other dependencies required, such as the Django framework." +msgstr "De applicatie heeft een databaseconnector nodig om de gegevens te kunnen opslaan. Daarvoor heb ik een tweetal requirements-bestanden gemaakt, waar alles al in staat wat nodig is. Zoals bijvoorbeeld Django en de databaseverbinding." + +#: ../../installation.rst:273 +msgid "The ``base.txt`` contains requirements which the application needs anyway, no matter which backend you've choosen." +msgstr "Het bestand ``base.txt`` bevat alle afhankelijkheden die de applicatie sowieso nodig heeft, ongeacht de databasekeuze die je gemaakt hebt." + +#: ../../installation.rst:277 +msgid "**Installation of the requirements below might take a while**, depending on your Internet connection, RaspberryPi speed and resources (generally CPU) available. Nothing to worry about. :]" +msgstr "**De installatie van de volgende afhankelijkheden kan enige tijd in beslag nemen**. Dit varieert en is sterk afhankelijk van de snelheid van je Internet-verbinding en je RaspberryPi. Je hoeft je dus niet zorgen te maken wanneer dit lang lijkt te duren. :]" + +#: ../../installation.rst:280 +msgid "PostgreSQL" +msgstr "PostgreSQL" + +#: ../../installation.rst:281 msgid "Did you choose PostgreSQL? Then execute these two lines::" msgstr "Heb je gekozen voor PostgreSQL? Voer dan deze twee regels uit::" -#: ../../installation.rst:278 +#: ../../installation.rst:288 +msgid "Did everything install without fatal errors? If the database client refuses to install due to missing files/configs, make sure you've installed ``postgresql-server-dev-all`` earlier in the process, when you installed the database server itself." +msgstr "Zonder problemen alles kunnen installeren? Mocht de database client niet willen installeren wegens missende bestanden, controleer dan of je eerder tijdens de installatie het volgende hebt uitgevoerd: als het goed is heb je ``postgresql-server-dev-all`` geïnstalleerd, tegelijkertijd met de databaseserver." + +#: ../../installation.rst:291 +msgid "Continue to chapter 8 (Bootstrapping)." +msgstr "Ga door naar hoofdstuk 8 (Bootstrapping)." + +#: ../../installation.rst:300 msgid "Or did you choose MySQL/MariaDB? Execute these two commands::" msgstr "Of heb je gekozen voor MySQL/MariaDB? Voer dan deze twee commando's uit::" -#: ../../installation.rst:285 -msgid "" -"Did everything install without fatal errors? If either of the database clients " -"refuses to install due to missing files/configs, make sure you've installed " -"``postgresql-server-dev-all`` (for **PostgreSQL**) or ``libmysqlclient-dev`` " -"(for **MySQL**) earlier in the process, when you installed the database server " -"itself." -msgstr "" -"Zonder problemen alles kunnen installeren? Mocht een van de database clients " -"niet willen installeren wegens missende bestanden, controleer dan of je eerder " -"tijdens de installatie het volgende hebt uitgevoerd: als het goed is heb je " -"``postgresql-server-dev-all`` (voor **PostgreSQL**) of ``libmysqlclient-dev`` " -"(voor **MySQL**) geïnstalleerd, tegelijkertijd met de databaseserver. Die zijn " -"namelijk hiervoor nodig." +#: ../../installation.rst:306 +msgid "Did everything install without fatal errors? If the database client refuses to install due to missing files/configs, make sure you've installed ``libmysqlclient-dev`` earlier in the process, when you installed the database server itself." +msgstr "Zonder problemen alles kunnen installeren? Mocht de database client niet willen installeren wegens missende bestanden, controleer dan of je eerder tijdens de installatie het volgende hebt uitgevoerd: als het goed is heb je ``libmysqlclient-dev`` geïnstalleerd, tegelijkertijd met de databaseserver." -#: ../../installation.rst:291 +#: ../../installation.rst:311 msgid "8. Bootstrapping" msgstr "8. Initialisatie" -#: ../../installation.rst:292 -msgid "" -"Now it's time to bootstrap the application and check whether all settings are " -"good and requirements are met." -msgstr "" -"Tijd om te kijken of alles goed is ingesteld. We gaan de applicatie proberen te " -"initialiseren." +#: ../../installation.rst:312 +msgid "Now it's time to bootstrap the application and check whether all settings are good and requirements are met." +msgstr "Tijd om te kijken of alles goed is ingesteld. We gaan de applicatie proberen te initialiseren." -#: ../../installation.rst:294 +#: ../../installation.rst:314 msgid "Execute this to initialize the database we've created earlier::" msgstr "Voer dit uit om de database te initialiseren::" -#: ../../installation.rst:298 -msgid "" -"Prepare static files for webinterface. This will copy all static files to the " -"directory we created for Nginx earlier in the process. It allows us to have " -"Nginx serve static files outside our project/code root." -msgstr "" -"Ga nu bezit met de statische bestanden voor de webinterface. Dit kopieert alle " -"statische bestanden in de map die we eerder, vlak na de installatie voor Nginx, " -"hebben aangemaakt. Het zorgt ervoor dat Nginx deze bestanden kan hosten buiten " -"de code-bestanden." - -#: ../../installation.rst:301 +#: ../../installation.rst:318 +msgid "Prepare static files for webinterface. This will copy all static files to the directory we created for Nginx earlier in the process. It allows us to have Nginx serve static files outside our project/code root." +msgstr "Ga nu bezit met de statische bestanden voor de webinterface. Dit kopieert alle statische bestanden in de map die we eerder, vlak na de installatie voor Nginx, hebben aangemaakt. Het zorgt ervoor dat Nginx deze bestanden kan hosten buiten de code-bestanden." + +#: ../../installation.rst:321 msgid "Sync static files::" msgstr "Synchroniseer statische bestanden::" -#: ../../installation.rst:305 -msgid "" -"Create an application superuser. Django will prompt you for a password. The " -"credentials generated can be used to access the administration panel inside the " -"application. Alter username and email if you prefer other credentials, but " -"email is not used in the application anyway." -msgstr "" -"Maak een gebruiker aan voor binnen de applicatie. Django vraagt je om een " -"wachtwoord te kiezen. Met deze gegevens kun je het beheerderspaneel binnen de " -"applicatie gebruiken. Indien gewenst kun je een andere gebruikersnaam kiezen. " -"Het e-mailadres maakt niet uit, want de applicatie ondersteunt toch geen e-mail." - -#: ../../installation.rst:308 +#: ../../installation.rst:325 +msgid "Create an application superuser. Django will prompt you for a password. The credentials generated can be used to access the administration panel inside the application. Alter username and email if you prefer other credentials, but email is not used in the application anyway." +msgstr "Maak een gebruiker aan voor binnen de applicatie. Django vraagt je om een wachtwoord te kiezen. Met deze gegevens kun je het beheerderspaneel binnen de applicatie gebruiken. Indien gewenst kun je een andere gebruikersnaam kiezen. Het e-mailadres maakt niet uit, want de applicatie ondersteunt toch geen e-mail." + +#: ../../installation.rst:328 msgid "Create your user::" msgstr "Creëer je eigen gebruiker::" -#: ../../installation.rst:314 -msgid "" -"Because you have shell access you may reset your user's password at any time " -"(in case you forget it). Just enter this for a password reset::" -msgstr "" -"Wachtwoord ooit vergeten? Via de command line kun je je wachtwoord (bij " -"verlies) hiermee aanpassen::" +#: ../../installation.rst:334 +msgid "Because you have shell access you may reset your user's password at any time (in case you forget it). Just enter this for a password reset::" +msgstr "Wachtwoord ooit vergeten? Via de command line kun je je wachtwoord (bij verlies) hiermee aanpassen::" -#: ../../installation.rst:318 +#: ../../installation.rst:338 msgid "You've almost completed the installation now." msgstr "Je bent op dit punt bijna klaar met de installatie." -#: ../../installation.rst:322 +#: ../../installation.rst:342 msgid "9. Webserver/Nginx (part 2)" msgstr "9. Webserver/Nginx (deel 2)" -#: ../../installation.rst:326 -msgid "" -"This installation guide asumes you run the Nginx webserver for this application " -"only." -msgstr "" -"Deze installatiehandleiding gaat er vanuit dat je de Nginx webserver alleen " -"gebruikt voor deze applicatie." +#: ../../installation.rst:346 +msgid "This installation guide asumes you run the Nginx webserver for this application only." +msgstr "Deze installatiehandleiding gaat er vanuit dat je de Nginx webserver alleen gebruikt voor deze applicatie." -#: ../../installation.rst:328 -msgid "" -"It's possible to have other applications use Nginx as well, but that requires " -"you to remove the wildcard in the ``dsmr-webinterface`` vhost, which you will " -"copy below." -msgstr "" -"Het is uiteraard mogelijk dat andere applicaties ook Nginx gebruiken, maar " -"daarvoor zul je de wildcard moet weghalen in de ``dsmr-webinterface`` vhost, " -"die je hieronder kopieert." - -#: ../../installation.rst:330 -msgid "" -"Go back to ``root`` / ``sudo`` user to configure the webserver (press ``CTRL + " -"D`` once)." -msgstr "" -"Ga terug naar de ``root`` / ``sudo``-gebruiker om de webserver in te stellen " -"(druk op ``CTRL + D``)." - -#: ../../installation.rst:332 -msgid "" -"Remove the default Nginx vhost (**only when you do not use it yourself, see the " -"note above**)::" -msgstr "" -"Verwijder de standaard vhost van Nginx **wanneer je deze niet zelf gebruikt** " -"(zie de notitie hierboven)::" - -#: ../../installation.rst:336 -msgid "" -"Copy application vhost, **it will listen to any hostname** (wildcard), but you " -"may change that if you feel like you need to. It won't affect the application " -"anyway::" -msgstr "" -"Kopieer de vhost voor de applicatie. Deze luistert standaard naar **elke " -"hostname** (wildcard), maar dat is natuurlijk naar eigen wens aan te passen::" - -#: ../../installation.rst:340 -msgid "" -"Let Nginx verify vhost syntax and reload Nginx when ``configtest`` passes::" -msgstr "" -"Laat Nginx controleren of je geen typefouten hebt gemaakt en herlaad Nginx " -"vervolgens wanneer de ``configtest`` lukt::" - -#: ../../installation.rst:349 +#: ../../installation.rst:348 +msgid "It's possible to have other applications use Nginx as well, but that requires you to remove the wildcard in the ``dsmr-webinterface`` vhost, which you will copy below." +msgstr "Het is uiteraard mogelijk dat andere applicaties ook Nginx gebruiken, maar daarvoor zul je de wildcard moet weghalen in de ``dsmr-webinterface`` vhost, die je hieronder kopieert." + +#: ../../installation.rst:350 +msgid "Go back to ``root`` / ``sudo`` user to configure the webserver (press ``CTRL + D`` once)." +msgstr "Ga terug naar de ``root`` / ``sudo``-gebruiker om de webserver in te stellen (druk op ``CTRL + D``)." + +#: ../../installation.rst:352 +msgid "Remove the default Nginx vhost (**only when you do not use it yourself, see the note above**)::" +msgstr "Verwijder de standaard vhost van Nginx **wanneer je deze niet zelf gebruikt** (zie de notitie hierboven)::" + +#: ../../installation.rst:356 +msgid "Copy application vhost, **it will listen to any hostname** (wildcard), but you may change that if you feel like you need to. It won't affect the application anyway::" +msgstr "Kopieer de vhost voor de applicatie. Deze luistert standaard naar **elke hostname** (wildcard), maar dat is natuurlijk naar eigen wens aan te passen::" + +#: ../../installation.rst:360 +msgid "Let Nginx verify vhost syntax and reload Nginx when ``configtest`` passes::" +msgstr "Laat Nginx controleren of je geen typefouten hebt gemaakt en herlaad Nginx vervolgens wanneer de ``configtest`` lukt::" + +#: ../../installation.rst:369 msgid "10. Supervisor" msgstr "10. Supervisor" -#: ../../installation.rst:350 -msgid "" -"Now we configure `Supervisor `_, which is used to run " -"our application's web interface and background jobs used. It's also configured " -"to bring the entire application up again after a shutdown or reboot." -msgstr "" -"We gaan nu `Supervisor `_ configureren, die gebruikt " -"wordt om de applicatie en achtergrondprocessen te draaien. Tevens zorgt " -"Supervisor ervoor dat deze processen bij het (opnieuw) opstarten automatisch " -"draaien." - -#: ../../installation.rst:353 +#: ../../installation.rst:370 +msgid "Now we configure `Supervisor `_, which is used to run our application's web interface and background jobs used. It's also configured to bring the entire application up again after a shutdown or reboot." +msgstr "We gaan nu `Supervisor `_ configureren, die gebruikt wordt om de applicatie en achtergrondprocessen te draaien. Tevens zorgt Supervisor ervoor dat deze processen bij het (opnieuw) opstarten automatisch draaien." + +#: ../../installation.rst:373 msgid "Copy the configuration file for Supervisor::" msgstr "Kopieer het configuratie-bestand voor Supervisor::" -#: ../../installation.rst:357 +#: ../../installation.rst:377 msgid "Login to ``supervisorctl`` management console::" msgstr "Wissel naar de ``supervisorctl`` beheerconsole::" -#: ../../installation.rst:361 -msgid "" -"Enter these commands (**listed after the** ``>``). It will ask Supervisor to " -"recheck its config directory and use/reload the files::" -msgstr "" -"Voer de volgende commando's in (**degene na de** ``>``). Dit zorgt ervoor dat " -"Supervisor zijn eigen configuratie opnieuw controleert en toepast::" - -#: ../../installation.rst:367 -msgid "" -"Three processes should be started or running. Make sure they don't end up in " -"``ERROR`` or ``BACKOFF`` state, so refresh with the ``status`` command a few " -"times." -msgstr "" -"Er draaien als het goed is altijd **drie** processen. Kijk goed of ze " -"uiteindelijk niet in ``ERROR`` of ``BACKOFF`` status terecht zijn gekomen. Je " -"kunt het overzicht verversen door ``status`` te typen." +#: ../../installation.rst:381 +msgid "Enter these commands (**listed after the** ``>``). It will ask Supervisor to recheck its config directory and use/reload the files::" +msgstr "Voer de volgende commando's in (**degene na de** ``>``). Dit zorgt ervoor dat Supervisor zijn eigen configuratie opnieuw controleert en toepast::" -#: ../../installation.rst:369 +#: ../../installation.rst:387 +msgid "Three processes should be started or running. Make sure they don't end up in ``ERROR`` or ``BACKOFF`` state, so refresh with the ``status`` command a few times." +msgstr "Er draaien als het goed is altijd **drie** processen. Kijk goed of ze uiteindelijk niet in ``ERROR`` of ``BACKOFF`` status terecht zijn gekomen. Je kunt het overzicht verversen door ``status`` te typen." + +#: ../../installation.rst:389 msgid "When still in ``supervisorctl``'s console, type::" msgstr "Typ het volgende wanneer je nog in ``supervisorctl``'s console bent::" -#: ../../installation.rst:373 +#: ../../installation.rst:393 msgid "Example of everything running well::" msgstr "Voorbeeld van wanneer alles naar behoren draait::" -#: ../../installation.rst:379 -msgid "" -"Want to check whether the datalogger works? Just tail it's log in supervisor " -"with::" -msgstr "" -"Wil je controleren of de datalogger zijn werk goed doet? Bekijk dan het " -"logbestand in supervisor met::" - -#: ../../installation.rst:383 -msgid "" -"You should see similar output as the ``cu``-command printed earlier in the " -"installation process." -msgstr "" -"Uiteindelijk zou je ongeveer dezelfde lap tekst moeten zien als toen we " -"handmatig gemeten hebben met het ``cu``-programma." - -#: ../../installation.rst:385 -msgid "" -"Want to quit supervisor? ``CTRL + C`` to stop tailing and then ``CTRL + D`` " -"once to exit supervisor command line." -msgstr "" -"Wil je uit supervisor? Druk dan op ``CTRL + C`` om het logbestand niet meer te " -"bekijken en vervolgens op ``CTRL + D`` om uit supervisor te gaan." - -#: ../../installation.rst:388 -msgid "" -"You now should have everything up and running! We're almost done and just need " -"to do a few last things on the next page." -msgstr "" -"Alles zou nu moeten werken! We zijn bijna klaar, op een paar laatste dingen na " -"in het volgende hoofdstuk." +#: ../../installation.rst:399 +msgid "Want to check whether the datalogger works? Just tail it's log in supervisor with::" +msgstr "Wil je controleren of de datalogger zijn werk goed doet? Bekijk dan het logbestand in supervisor met::" + +#: ../../installation.rst:403 +msgid "You should see similar output as the ``cu``-command printed earlier in the installation process." +msgstr "Uiteindelijk zou je ongeveer dezelfde lap tekst moeten zien als toen we handmatig gemeten hebben met het ``cu``-programma." + +#: ../../installation.rst:405 +msgid "Want to quit supervisor? ``CTRL + C`` to stop tailing and then ``CTRL + D`` once to exit supervisor command line." +msgstr "Wil je uit supervisor? Druk dan op ``CTRL + C`` om het logbestand niet meer te bekijken en vervolgens op ``CTRL + D`` om uit supervisor te gaan." + +#: ../../installation.rst:408 +msgid "You now should have everything up and running! We're almost done and just need to do a few last things on the next page." +msgstr "Alles zou nu moeten werken! We zijn bijna klaar, op een paar laatste dingen na in het volgende hoofdstuk." + +#~ msgid "" +#~ msgstr "" + +#~ msgid "Contents" +#~ msgstr "Inhoudsopgave" diff --git a/docs/locale/nl/LC_MESSAGES/intro.mo b/docs/locale/nl/LC_MESSAGES/intro.mo index e910a916b33c3259ef7533dae4dd0107da486822..0aad4fe0900f5ec4389af0f3a21fa912028ef631 100644 GIT binary patch delta 371 zcmXxgF-yZh7{>AE&a~CqI2fo)2ZwG_j2Sc(9Hokg)T<*Qgcl9ypek?~1qLxUF+>(U+5UX7$<+z8>c!Nb; z^U?)oSivVe#ur>bKPRnV1$VHH1w6+CyhM6+HD(g=VxM8i=0~{A^Muu}xJfr__{ngG zU$}_9l5~Xww2e#iQWax7!8+QyYdpk0zTrFaiS9Y2Q%j=1c&9S4o5aK#TFo~8o6i1_ sP3^G%WjD1ZKAgFAAKKBWi?R@zGs4=)BumgG`v(1VcTL90>}y@*V9Uv?)MX2R^Gp zVk)+)LOjR8K8Q!uk@XEtn&1`e|DfAP@bdA)#=pRq*#8Dkg3lI(7=!P?(4dCytKbTF z54-?|yvN{o@CA4ajF*J?g#Mzy2egDi7W$S>K&uQ4Q$`K%AQA!>F9SM90f{og1%eyF zp%ACA!cak9T-6h~ms8&{leaX^nd-%Z%G%tNjaQCIjz(I=(kp97nuL@;pHplTCY95~ zDeu{kGPGqAGaaQV2l-AT^ zy5yZoQ+CKmc*G`ACMDcq&yK0*>?CK0i)d-mu}qmpj{8V9F-L`+e^{w)G+S*v)M|BF zt>Q;@y;8q1OYV@-OZS`C*szn{x(?m8oG4H2XfwJPwTpv=*K^Y@Q_30Z|197JCZnDj z^f\n" -"POT-Creation-Date: 2016-01-01 00:00+0100\n" +"POT-Creation-Date: 2017-02-18 00:28+0100\n" "PO-Revision-Date: 2017-01-01 00:00+0100\n" "Last-Translator: Dennis Siemensma \n" "Language-Team: Dennis Siemensma \n" @@ -16,8 +16,6 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.3.4\n" -"Language: nl\n" -"X-Generator: Poedit 1.8.7.1\n" #: ../../intro.rst:2 msgid "Introduction" @@ -38,8 +36,8 @@ msgid "" "Keeping your data for yourself (all data is stored locally and untracked " "as well)." msgstr "" -"Alle gegevens zijn eigendom van jezelf (alle data wordt lokaal opgeslagen " -"en wordt niet gedeeld met de buitenwereld)." +"Alle gegevens zijn eigendom van jezelf (alle data wordt lokaal opgeslagen" +" en wordt niet gedeeld met de buitenwereld)." #: ../../intro.rst:8 msgid "Always free to use (it's open source on Github as well)." @@ -52,22 +50,23 @@ msgstr "Waarom?" #: ../../intro.rst:13 msgid "" "Because open-source triggers the community to collaborate even more and " -"bring out the best ideas! In the last year, many other cool DSMR-projects " -"were launched as well!" +"bring out the best ideas! In the last year, many other cool DSMR-projects" +" were launched as well!" msgstr "" "Omdat open-source het beste in een community naar boven brengt en zorgt " -"voor nieuwe ideëen of inzichten. In het afgelopen jaar zijn er tevens tal " -"andere coole DSMR-projecten gestart!" +"voor nieuwe ideëen of inzichten. In het afgelopen jaar zijn er tevens tal" +" andere coole DSMR-projecten gestart!" #: ../../intro.rst:17 msgid "Languages" msgstr "Talen" #: ../../intro.rst:18 +#, fuzzy msgid "" -"The entire application and it's code is written in English. The entire " -"interface however is also translated into Dutch and will be triggered " -"depending on you browser's language preference." +"The entire application and it's code is written in English. The interface" +" is also translated into Dutch and will be triggered depending on your " +"browser's language preference." msgstr "" "De gehele applicatie, en bijbehorende code, is in het Engels geschreven. " "De grafische interface is echter ook in het Nederlands beschikbaar. Deze " @@ -79,8 +78,8 @@ msgstr "Vaardigheid" #: ../../intro.rst:23 msgid "" -"The project is well documented, but requires a certain 'Unix skill' as you " -"will need to install several dependencies using the command line." +"The project is well documented, but requires a certain 'Unix skill' as " +"you will need to install several dependencies using the command line." msgstr "" "Het project is behoorlijk gedocumenteerd, maar vereist desondanks een " "zekere Unix-vaardigheid. Je zult namelijk handmatig diverse " @@ -88,11 +87,12 @@ msgstr "" #: ../../intro.rst:25 msgid "" -"I advise to only use this tool when you have basic Linux knowledge or have " -"any interest in the components used." +"I advise to only use this tool when you have basic Linux knowledge or " +"have any interest in the components used." msgstr "" "Ik raad je aan deze tool alleen te gebruiken wanneer je enige Linux-" -"basiskennis hebt. Of wanneer je interesse hebt in de gebruikte componenten." +"basiskennis hebt. Of wanneer je interesse hebt in de gebruikte " +"componenten." #: ../../intro.rst:29 msgid "Github" @@ -105,3 +105,4 @@ msgid "" msgstr "" "Je kunt het project hier vinden: https://github.com/dennissiemensma/dsmr-" "reader" + diff --git a/docs/locale/nl/LC_MESSAGES/screenshots.mo b/docs/locale/nl/LC_MESSAGES/screenshots.mo index 9fc5e1a159c259999af624be42c456bb08f45c25..891aa6e5aa9516b808ea6cc94c5cb140aa17e98c 100644 GIT binary patch delta 648 zcmX}p%PYiD6u|K_509BK9^+lJKzT&OXfT?Ep;<6B%0_l$CrXqb3u^cSEc7$GNm&sVRT{?b^aJ`=#nvB3_kqg92$0!X?(*` zotPssgL}A%b^NX0&rmn=Qr#d%P!~?%048w~A90apB2>YvoKy80UZX=>8mBDnWD2!H zgGU1{V-s$pc5;ISc%ShVb;B<_#c!O&6DD7xkI4)8gIe&sTVx5Z@DL+~A~8MEydsfK zoWNmBqAvW7LHxuOY%dnkTVa?k6r_UW;L-(ZciCWVDa{VBoGi(V^{O?h$WR#%y&ny( zPS_(IdLk4moce!g_ga_+w`C<#FqV{WB>L`E5;_hy3_qBF()pYoK h{XOQKbJ1*Z8Rms+%QOmt=7_sLb?lDYQy-oo%O4~TNv;3@ delta 1496 zcmZva&ud&&6vuCpv7L<8YOU4Q3TIT(^pOk`T2w~s!iW+`YjM-yrrw!%X5LL+?w#Iu zU&bWjD2Re9%T&RQC`h+jvyr+G6gS$1ZN;6%jbOlqe}VWtZ>DrWFLUSf?$2|+=X<}Z zUY+gVI#Bvhp*@Oz6umT|)N$}HP}&ERO6>(Nf_?Dg(fII`Qe}**;4~P4d%%<6G4L7i zZLkH_z(2sd!GopYIRYP-E05!&f`!wdT(AOu0-gtR@EGSFpJYehGdC zR*|L5e-Fy}N06Naz6vgZyP({E0@*Ht4RBQ?y@`+Cp>`J(r9UFgi{K3qQ!2h^c+i3} z&Ou4I56*z^gP(#|z*+E>eM6<&Ag0uNU<6(ojlTsYk!#?0Qqr6FxBz~1uTnpO<^4+a zz+XU7w0xgZZ-AeJ-+8l0NER9l{UM)XW18FzIeLH7y;Cvsml#27BBQJI*M}yIto4byF9Du^rNOlQ`v8@TO(L zCV39Iw;V^4QEf0i_2OgWv1a~v>(1$^>r;L9+;(2#dt~6*9t)(?p5Dx;<8?R5$hBp4 zos2EA%vzq=W{C^goz(M;eMY^+iQq!49GRn@Nz>t2$FUJ*I>o)XV08OYWNu@`j&I*T zR)w7-d%u|2_vCzi0Y9qO8}<6&*Yft@-SYh4`RR9Nm$mKWy2A~!X=P>pCARE!aK1rj z9U~kq)Sj+ARa+SRFnxK?l1*G54^}Iu`sWxWWxt^`jmZy~VHJE>SK z+u-Ed&`CBSf`gYUi_xp&@n`;fV&pwe?EG1ItJHr1Nw{^&f`%?Uogyh~So{oTHI|CE z4X;6sD2JUfZ{byr`#IFdC_vNaW=%|u4HLGBwqbEliYD7R+RD=ucR6T)sl0%1em!`N bI1WzS4o6!CD@}u9O2j*_oOjy$mnZ%OC-q|Y diff --git a/docs/locale/nl/LC_MESSAGES/screenshots.po b/docs/locale/nl/LC_MESSAGES/screenshots.po index 6d4394659..384ca2f29 100644 --- a/docs/locale/nl/LC_MESSAGES/screenshots.po +++ b/docs/locale/nl/LC_MESSAGES/screenshots.po @@ -8,17 +8,14 @@ msgid "" msgstr "" "Project-Id-Version: DSMR Reader v1.x\n" "Report-Msgid-Bugs-To: Dennis Siemensma \n" -"POT-Creation-Date: 2016-01-01 00:00+0100\n" +"POT-Creation-Date: 2017-02-16 15:58+0100\n" "PO-Revision-Date: 2017-01-01 00:00+0100\n" "Last-Translator: Dennis Siemensma \n" -"Language-Team: Dennis Siemensma \n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.3.4\n" -"Language: nl\n" -"X-Generator: Poedit 1.8.7.1\n" #: ../../screenshots.rst:2 msgid "Screenshots" @@ -26,165 +23,143 @@ msgstr "Screenshots" #: ../../screenshots.rst:3 msgid "" -"Below you can find some screenshots of the application. Please read the note " -"below regarding solar panels and support for them." +"Below you can find some screenshots of the application. Please read the " +"note below regarding solar panels and support for them." msgstr "" -"Hieronder staan enkele screenshots van de applicatie. Lees hieronder ook de " -"notitie met betrekking tot zonnepanelen en de ondersteuning daarvoor." - -#: ../../screenshots.rst -msgid "Contents" -msgstr "Inhoud" +"Hieronder staan enkele screenshots van de applicatie. Lees hieronder ook " +"de notitie met betrekking tot zonnepanelen en de ondersteuning daarvoor." #: ../../screenshots.rst:11 -msgid "Solar panels & electricity returned" -msgstr "Zonnepanelen & teruglevering electriciteit" - -#: ../../screenshots.rst:12 -msgid "" -"Note that **I do not have solar panels at home**, but the application however " -"**does support plotting any electricity returned**." -msgstr "" -"Wees ervan bewust dat **ik thuis geen zonnepanelen heb**, maar dat de " -"applicatie daar **wel ondersteuning voor heeft qua weergave teruglevering " -"elektriciteit**." - -#: ../../screenshots.rst:14 -msgid "" -"Therefor there aren't always graphs of them in the screenshots, but the users " -"who do have them, will have additional green graphs rendered in the " -"application." -msgstr "" -"Daarom staan er daar niet altijd grafieken van in deze screenshots, maar de " -"gebruikers die ze wel thuis hebben, zullen overal een extra groene grafiek " -"zien binnen de applicatie." - -#: ../../screenshots.rst:18 msgid "Dashboard" msgstr "Dashboard" -#: ../../screenshots.rst:19 +#: ../../screenshots.rst:12 msgid "" -"The dashboard displays the latest information regarding any consumption of " -"today and the current month so far." +"The dashboard displays the latest information regarding any consumption " +"of today and the current month so far." msgstr "" -"Het dashboard weergeeft de meest recente informatie over je energieverbruik " -"van vandaag en de lopende maand tot nu toe." +"Het dashboard weergeeft de meest recente informatie over je " +"energieverbruik van vandaag en de lopende maand tot nu toe." -#: ../../screenshots.rst:27 +#: ../../screenshots.rst:20 msgid "Archive" msgstr "Archief" -#: ../../screenshots.rst:28 +#: ../../screenshots.rst:21 msgid "" "The archive allows you to go back to any moment tracked. The data can be " "plotted either on day, month or year level." msgstr "" -"Het archief stelt je in staat om terug in de tijd te gaan naar elke moment dat " -"gemeten is met de applicatie. Gegevens kunnen getoond worden op verschillende " -"detailniveaus: per dag, per maand en per jaar." +"Het archief stelt je in staat om terug in de tijd te gaan naar elke " +"moment dat gemeten is met de applicatie. Gegevens kunnen getoond worden " +"op verschillende detailniveaus: per dag, per maand en per jaar." -#: ../../screenshots.rst:36 +#: ../../screenshots.rst:29 msgid "Trends" msgstr "Trends" -#: ../../screenshots.rst:37 +#: ../../screenshots.rst:30 msgid "Trends are an average summary of your daily consumption and habits." msgstr "Trends weergeven je gemiddelde energieverbruik en gewoontes." -#: ../../screenshots.rst:45 +#: ../../screenshots.rst:38 msgid "Statistics" msgstr "Statistieken" -#: ../../screenshots.rst:46 +#: ../../screenshots.rst:39 msgid "" "The statistics page will display the current state of your meter and the " "energy prices currently apply (if any)." msgstr "" -"De statistiekenpagina weergeeft de huidige staat van je slimme meter en de " -"huidige energietarieven (wanneer van toepassing)." +"De statistiekenpagina weergeeft de huidige staat van je slimme meter en " +"de huidige energietarieven (wanneer van toepassing)." -#: ../../screenshots.rst:54 +#: ../../screenshots.rst:47 msgid "Compare" msgstr "Vergelijk" -#: ../../screenshots.rst:55 +#: ../../screenshots.rst:48 msgid "This page allows you to compare two days, months or years tracked before." msgstr "" -"Met deze pagina vergelijk je eenvoudig twee dagen, maanden of jaren met elkaar." +"Met deze pagina vergelijk je eenvoudig twee dagen, maanden of jaren met " +"elkaar." -#: ../../screenshots.rst:63 +#: ../../screenshots.rst:56 msgid "Status" msgstr "Status" -#: ../../screenshots.rst:64 +#: ../../screenshots.rst:57 msgid "" "The status page will show the 'health' of the application and any data " -"tracked. If there are any problems regarding data handling, they should be " -"indicated here." +"tracked. If there are any problems regarding data handling, they should " +"be indicated here." msgstr "" -"De statuspagina weergeeft de 'gezondheid' van de applicatie en die van de " -"dataverwerking. Mochten er problemen zijn met het verzamelen van gegevens dan " -"zou dat hier zichtbaar moeten zijn." +"De statuspagina weergeeft de 'gezondheid' van de applicatie en die van de" +" dataverwerking. Mochten er problemen zijn met het verzamelen van " +"gegevens dan zou dat hier zichtbaar moeten zijn." -#: ../../screenshots.rst:72 +#: ../../screenshots.rst:65 msgid "Export" msgstr "Exporteren" -#: ../../screenshots.rst:73 +#: ../../screenshots.rst:66 msgid "" -"Want to export day totals or hourly data to Excel? This page allows you to " -"export the data in .CSV format." +"Want to export day totals or hourly data to Excel? This page allows you " +"to export the data in .CSV format." msgstr "" -"Wil je alle dag- of uurtotalen exporteren om in Excel te bekijken? Dat kan via " -"deze pagina door ze te exporteren in .CSV-formaat." +"Wil je alle dag- of uurtotalen exporteren om in Excel te bekijken? Dat " +"kan via deze pagina door ze te exporteren in .CSV-formaat." -#: ../../screenshots.rst:81 +#: ../../screenshots.rst:74 msgid "Settings" msgstr "instellingen" -#: ../../screenshots.rst:82 +#: ../../screenshots.rst:75 msgid "" "The project is written using Django and some of it's backend pages are " "displayed below." msgstr "" -"Het project is gemaakt met Django en hieronder staan enkele beheerderspagina's " -"daarvan." +"Het project is gemaakt met Django en hieronder staan enkele " +"beheerderspagina's daarvan." -#: ../../screenshots.rst:84 +#: ../../screenshots.rst:77 msgid "" "The application has quite some features, such are temperature tracking, " -"automated backups and Dropbox intergration. This page displays the status of " -"them all." +"automated backups and Dropbox intergration. This page displays the status" +" of them all." msgstr "" "De applicatie heeft behoorlijk wat features, zoals buitentemperatuur " -"bijhouden, geautomatiseerde back-ups en Dropbox-integratie. Op deze pagina kun " -"je een overzicht vinden van alle instellingen." +"bijhouden, geautomatiseerde back-ups en Dropbox-integratie. Op deze " +"pagina kun je een overzicht vinden van alle instellingen." -#: ../../screenshots.rst:91 +#: ../../screenshots.rst:84 msgid "Here you may manage your energy prices:" msgstr "Hier kun je je energieprijzen beheren:" -#: ../../screenshots.rst:97 +#: ../../screenshots.rst:90 msgid "This allows you to alter your backup settings:" msgstr "Hiermee beheer je de instellingen voor je back-ups:" -#: ../../screenshots.rst:103 +#: ../../screenshots.rst:96 msgid "Pick your own colors for the graphs displayed:" msgstr "Kies je eigen kleuren voor de grafieken:" -#: ../../screenshots.rst:109 +#: ../../screenshots.rst:102 msgid "" -"The application supports the daily export of your gas meter positions (if any) " -"to your personal mindergas.nl account." +"The application supports the daily export of your gas meter positions (if" +" any) to your personal mindergas.nl account." msgstr "" -"De applicatie ondersteunt het dagelijks exporteren van je gasmeterstanden naar " -"je eigen account bij mindergas.nl." +"De applicatie ondersteunt het dagelijks exporteren van je gasmeterstanden" +" naar je eigen account bij mindergas.nl." -#: ../../screenshots.rst:115 +#: ../../screenshots.rst:108 msgid "" -"There are several additional backend pages for the other configuration options " -"as well." +"There are several additional backend pages for the other configuration " +"options as well." msgstr "" "Er zijn nog diverse andere beheerpagina's beschikbaar voor de overige " "configuratie-instellingen." + +#~ msgid "Contents" +#~ msgstr "Inhoud" + diff --git a/docs/locale/nl/LC_MESSAGES/settings.mo b/docs/locale/nl/LC_MESSAGES/settings.mo new file mode 100644 index 0000000000000000000000000000000000000000..c21f2a46af79923a3bcc320fcc85ba1fce6f0b0d GIT binary patch literal 10294 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 Q9IbsPNJ&S%)3MC_Kce8rivR!s literal 0 HcmV?d00001 diff --git a/docs/locale/nl/LC_MESSAGES/settings.po b/docs/locale/nl/LC_MESSAGES/settings.po new file mode 100644 index 000000000..a0c58571e --- /dev/null +++ b/docs/locale/nl/LC_MESSAGES/settings.po @@ -0,0 +1,386 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) 2016, Dennis Siemensma +# This file is distributed under the same license as the DSMR Reader +# package. +# FIRST AUTHOR , 2017. +# +msgid "" +msgstr "" +"Project-Id-Version: DSMR Reader 1.x\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-02-19 16:32+0100\n" +"PO-Revision-Date: 2017-02-19 18:18+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.3.4\n" +"Language: nl\n" +"X-Generator: Poedit 1.8.7.1\n" + +#: ../../settings.rst:2 +msgid "Settings" +msgstr "Instellingen" + +#: ../../settings.rst:4 +msgid "" +"The application has several settings available, which you can edit in the " +"Configuration page. The default settings should work fine, although it's " +"recommended to enable syncing backups using Dropbox." +msgstr "" +"De applicatie heeft diverse instellingen die je kunt bewerken in de " +"Configuratie-pagina. De standaardinstellingen zouden afdoende moeten werken, " +"al is het wel aan te raden de back-ups te synchroniseren via Dropbox." + +#: ../../settings.rst:11 +msgid "Database/Django settings" +msgstr "Database/Django instellingen" + +#: ../../settings.rst:13 +msgid "``dsmrreader/settings.py``" +msgstr "``dsmrreader/settings.py``" + +#: ../../settings.rst:14 +msgid "" +"In case you want to alter the database settings, or any other Django " +"settings, please modify (or add) them to the ``dsmrreader/settings.py`` file." +msgstr "" +"Wanneer je de database-instellingen (of die van Django) wilt wijzigen, voer " +"deze dan door in ``dsmrreader/settings.py``." + +#: ../../settings.rst:16 +msgid "" +"Make sure to reload the application afterwards to persist the changes you've " +"made, by executing ``./reload.sh`` or restarting the Supervisor processes." +msgstr "" +"Zorg ervoor dat je de applicatie herlaad na je wijzigingen, door ``./reload." +"sh`` uit te voeren, of de Supervisor-processen te herstarten." + +#: ../../settings.rst:20 +msgid "API configuration" +msgstr "API-configuratie" + +#: ../../settings.rst:22 +msgid "" +"The application does have an API, but it's disabled by default. You can " +"enable it by activating the \"Allow API calls\" option." +msgstr "" +"De applicatie heeft een API, maar die is standaard uitgeschakeld. Je kunt " +"deze inschakelen met de \"Sta API-calls toe\" optie." + +#: ../../settings.rst:26 +msgid "``Allow API calls``" +msgstr "``Sta API-calls toe``" + +#: ../../settings.rst:27 +msgid "Whether the API is enabled." +msgstr "Geeft aan of de API beschikbaar is voor gebruik." + +#: ../../settings.rst:30 +msgid "``Auth Key``" +msgstr "``Authorisatiesleutel``" + +#: ../../settings.rst:31 +msgid "The auth key used for authentication." +msgstr "De autorisatiesleutel om toegang te krijgen tot de API." + +#: ../../settings.rst:36 +msgid "Backup configuration" +msgstr "Backupconfiguratie" + +#: ../../settings.rst:37 +msgid "" +"The application creates a daily database backup by default. You choose " +"whether you want to have it compressed or in raw SQL form. The timestamp of " +"the backup can be altered as well." +msgstr "" +"De applicatie maakt standaard dagelijks een databaseback-up. Je kunt hiermee " +"aangegeven in welke compressievorm en tevens het tijdstip van de back-up." + +#: ../../settings.rst:42 +msgid "``Backup daily``" +msgstr "``Dagelijkse backup``" + +#: ../../settings.rst:43 +msgid "Whether to created backups at all." +msgstr "Maakt een dagelijkse backup van je gegevens." + +#: ../../settings.rst:46 +msgid "``Compress``" +msgstr "``Comprimeren``" + +#: ../../settings.rst:47 +msgid "" +"Enable this to have the backups compressed in gzip format. Highly " +"recommended as it will make backups up to 10 times smaller!" +msgstr "" +"Zet dit aan om de back-ups in gzip-formaat op te slaan. Dit wordt sterk " +"aanbevolen, gezien het de back-ups tot 10 x kleiner maakt!" + +#: ../../settings.rst:51 +msgid "``Backup timestamp``" +msgstr "``Tijdstip van backup``" + +#: ../../settings.rst:52 +msgid "Timestamp of the daily backup." +msgstr "Voorkeurstijdstip van dagelijkse backup." + +#: ../../settings.rst:57 +msgid "Dropbox configuration" +msgstr "Dropbox-configuratie" + +#: ../../settings.rst:58 +msgid "" +"There is a Dropbox integration available to safely transfer each daily " +"backup into your Dropbox account. :doc:`More information about this feature " +"can be found in the FAQ`." +msgstr "" +"Er is een koppeling mogelijk met je eigen Dropbox-account om de back-ups " +"veilig te stellen. :doc:`Meer informatie over deze feature kun je " +"terugvinden in de FAQ`." + +#: ../../settings.rst:62 +msgid "``Dropbox access token``" +msgstr "``Dropbox 'access token'``" + +#: ../../settings.rst:63 +msgid "" +"Enter your Dropbox access token here. Leave blank or clear to disable " +"Dropbox integration." +msgstr "" +"Voer hier je Dropbox-access token in. Laat leeg om de Dropbox-koppeling uit " +"te schakelen." + +#: ../../settings.rst:68 +msgid "Consumption configuration" +msgstr "Verbruiksconfiguratie" + +#: ../../settings.rst:69 +msgid "" +"The consumption settings determine how the application should handle the " +"separate readings. The default behaviour is to group all readings each " +"minute. This can be disabled." +msgstr "" +"De verbruiksinstellingen bepalen hoe de applicatie omgaat met de individuele " +"metingen. Standaard groepeert de applicatie de metingen per minuut." + +#: ../../settings.rst:73 +msgid "``Compactor grouping type``" +msgstr "``Metingen groeperen``" + +#: ../../settings.rst:74 +msgid "The density of the readings, visible in the application as consumption." +msgstr "" +"De dichtheid van de metingen, zoals getoond als verbruik in de applicatie." + +#: ../../settings.rst:79 +msgid "Energy supplier prices" +msgstr "Tarieven energieleverancier" + +#: ../../settings.rst:80 +msgid "" +"You can enter all your energy contract prices here. The application will use " +"them (when available) to calculate the consumption of each day. :doc:`See " +"the FAQ on how to retroactivily adjust prices (if needed)`." +msgstr "" +"Je kunt hier je energietarieven invoeren. De applicatie gebruikt deze dan om " +"je dagelijkse verbruik te berekenen. :doc:`Zie de FAQ hoe je dit eventueel " +"met terugwerkende kracht kan doen (indien nodig)`." + +#: ../../settings.rst:87 +msgid "Datalogger configuration" +msgstr "Dataloggerconfiguratie" + +#: ../../settings.rst:88 +msgid "This configuration applies to how to read your smart meter." +msgstr "Deze configuratie bepaalt hoe je slimme meter uitgelezen wordt." + +#: ../../settings.rst:91 +msgid "``Poll P1 port``" +msgstr "``Peil P1 poort``" + +#: ../../settings.rst:92 +msgid "Do not disable this. Will be removed next release." +msgstr "Niet aankomen, wordt bij de volgende release verwijderd." + +#: ../../settings.rst:95 +msgid "``Track electricity phases``" +msgstr "``Houd elektriciteitsfasen bij``" + +#: ../../settings.rst:96 +msgid "" +"Whether you want to track phases. :doc:`More information about this feature " +"can be found in the FAQ`." +msgstr "" +"Geeft aan of we de elektriciteitsfasen moeten bijhouden (wanneer aanwezig). :" +"doc:`Meer informatie over deze feature kun je terugvinden in de FAQ`." + +#: ../../settings.rst:100 +msgid "``Verify telegram CRC``" +msgstr "``Controleer de CRC van telegrammen``" + +#: ../../settings.rst:101 +msgid "" +"Whether the application should verify the incoming data. Only available for " +"DSMR 4+." +msgstr "" +"Geeft aan of we de CRC (checksum) van binnenkomende telegrammen moeten " +"controleren. Alleen beschikbaar voor DSMR 4+." + +#: ../../settings.rst:104 +msgid "``DSMR version``" +msgstr "``DSMR-versie``" + +#: ../../settings.rst:105 +msgid "" +"The DSMR version your smart meter has. Used to determine how the serial " +"connection should work." +msgstr "" +"De DSMR-versie die je slimme meter ondersteunt. Wordt gebruikt om te bepalen " +"hoe de seriele verbinding werkt." + +#: ../../settings.rst:108 +msgid "``COM-port``" +msgstr "``COM-poort``" + +#: ../../settings.rst:109 +msgid "The COM port your cable can be read from." +msgstr "COM-poort die verbonden is met je slimme meter." + +#: ../../settings.rst:114 +msgid "Frontend configuration" +msgstr "Interfaceconfiguratie" + +#: ../../settings.rst:115 +msgid "This applies to the visualisation in the application." +msgstr "Dit heeft betrekking op de visuele weergave in de applicatie." + +#: ../../settings.rst:118 +msgid "``Merge electricity tariffs``" +msgstr "``Voeg tarieven samen``" + +#: ../../settings.rst:119 +msgid "" +"Whether to merge the high and low tariffs. :doc:`More information about this " +"feature can be found in the FAQ`." +msgstr "" +"Bepaalt of de elektriciteitstarieven samengevoegd moeten worden (wanneer je " +"voor een enkel tarief betaalt). :doc:`Meer informatie over deze feature kun " +"je terugvinden in de FAQ`." + +#: ../../settings.rst:123 +msgid "``**** color``" +msgstr "``Kleur ****``" + +#: ../../settings.rst:124 +msgid "Multiple colors can be set here for the graphs." +msgstr "Je kunt hier diverse kleuren instellen voor de grafieken." + +#: ../../settings.rst:129 +msgid "MinderGas.nl configuration" +msgstr "MinderGas.nl-configuratie" + +#: ../../settings.rst:130 +msgid "" +"Optional connection with your account at MinderGas.nl. :doc:`More " +"information about this feature can be found in the FAQ`." +msgstr "" +"Optionele integratie met je MinderGas.nl-account. :doc:`Meer informatie over " +"deze feature kun je terugvinden in de FAQ`." + +#: ../../settings.rst:135 +msgid "``Export data to MinderGas``" +msgstr "``Exporteer gegevens naar MinderGas``" + +#: ../../settings.rst:136 +msgid "Whether to enable the connecting with MinderGas." +msgstr "" +"Bepaalt of we je meterstanden dagelijks moeten uploaden naar je eigen " +"account op MinderGas.nl." + +#: ../../settings.rst:139 +msgid "``MinderGas authentication token``" +msgstr "``MinderGas.nl Authenticatietoken (API)``" + +#: ../../settings.rst:140 +msgid "API token for your MinderGas.nl account." +msgstr "" +"Authenticatietoken voor de API-toegang van je persoonlijk account bij " +"MinderGas." + +#: ../../settings.rst:145 +msgid "Notes" +msgstr "Notities" + +#: ../../settings.rst:146 +msgid "" +"You can leave personal notes for yourself here. Such as when you were on " +"holiday or experimented with the heater settings." +msgstr "" +"Je kunt hier persoonlijke notities voor jezelf achterlaten. Zoals wanneer je " +"op vakantie bent of hebt geëxperimenteerd met de verwarming." + +#: ../../settings.rst:152 +msgid "Notification configuration" +msgstr "Notificatieconfiguratie" + +#: ../../settings.rst:153 +msgid "" +"Allows sending daily notifications to your phone. :doc:`More information " +"about this feature can be found in the FAQ`." +msgstr "" +"Bepaalt of je een dagelijkse notificatie wilt ontvangen op je smartphone " +"over je energieverbruik. :doc:`Meer informatie over deze feature kun je " +"terugvinden in de FAQ`." + +#: ../../settings.rst:157 +msgid "``Send notification``" +msgstr "``Stuur notificatie``" + +#: ../../settings.rst:158 ../../settings.rst:176 +msgid "Whether to enable this feature." +msgstr "Geeft aan of deze feature aanstaat." + +#: ../../settings.rst:161 +msgid "``Notification service``" +msgstr "``Notificatieservice``" + +#: ../../settings.rst:162 +msgid "The notification service you are using." +msgstr "De notificatieservice die je gebruikt." + +#: ../../settings.rst:165 +msgid "``Notification service API key``" +msgstr "``API sleutel voor notificatie service``" + +#: ../../settings.rst:166 +msgid "API token for your account of the notification service." +msgstr "" +"De API sleutel die gebruikt wordt om notificaties naar je smartphone te " +"sturen. " + +#: ../../settings.rst:170 +msgid "Weather configuration" +msgstr "Weergegevensconfiguratie" + +#: ../../settings.rst:171 +msgid "" +"There is support for tracking outside temperatures for a fixed number of " +"weather stations. :doc:`More information about this feature can be found in " +"the FAQ`." +msgstr "" +"Er is ondersteuning voor het uitlezen van de temperatuur :doc:`Meer " +"informatie over deze feature kun je terugvinden in de FAQ`." + +#: ../../settings.rst:175 +msgid "``Track weather``" +msgstr "``Houd weergegevens bij``" + +#: ../../settings.rst:179 +msgid "``Buienradar weather station``" +msgstr "``Buienradar weerstation``" + +#: ../../settings.rst:180 +msgid "The fixed weather station you wish to use." +msgstr "Het weerstation die je wilt gebruiken." diff --git a/docs/locale/nl/LC_MESSAGES/troubleshooting.mo b/docs/locale/nl/LC_MESSAGES/troubleshooting.mo new file mode 100644 index 0000000000000000000000000000000000000000..e792d96033ca007dba53ee86d07d81c8240a9e6e GIT binary patch literal 3375 zcmaJ@O>ZN|5$(iIY%2)@e*p%ZLj^g+!D>e0`fE)mUT9asdTqy^qs~(D^wO$h#m1er9>Q&Y2dh_2Gp8i(h_e)&A z!SxNU=W+c9m;C4_N(EfM#q~1o|M63$9>M+#_8HjUJ*Ctaus2|T0sB|j9oTPSZ{VGO z!u}ce|9)DjU&DUzGo@a~^Uq;Fg#G)^mHG?pcX0L+*1vpCsRlN}ivRCmJJ|oh{tEU} zI2Zp7{=9W?RO#aD!gjxS2SNREE`AHnWQ-G=fOCdFdaOzoH z>cIIl;Xr<#jCW)rB~M8kOL$DL1s=0Ye<17INXF4=H|MZ0(T9?bT*8a8ZR}kN-qKt< zwzM>9LZeaaYEN;!f1K=SMB3GqF6NB&9HeOI;mL!$N2jMB9~>WH1EM$HTE8UkxTG_9 zp9eqY7|H1wN78|FOe{yb@Et{FT29#YH%W)Yh;bd&F8PpmjJ2clE+#@=fDfEWr!MxP z#TQXTiogZX@J z%~Oqf*^P^Yl2W`%Ol#x4=zs!!GB69IXX7 zel+JXDr_%y*X0ByBp^jUW2(98+7`a092q*hx>TpR%3w&#YC|F={r!GK&@BBvl3zL@ zU1O~DJkpY_-E^ff!Xq?FI0=h32t(15+JLgjhYPGkQ}cr6a%f22e{g%Ur9*1VEfyJHhaSa5l-fkNxX7vI424!W`dG5MZ(gmFzB+jTcUzqW-+_T~;=M3OeYSl- z7KWF(G@I70ySEEUfJM1_pahO8YM9R=sEjD6NXuat9jv2%3hdmFA`*raNhlqhYq{GwW6FSM{ph5X)=Y;1z zq~bWXrY`PuZ7k0GkaiwEI4kagDKa#QLnJz+oBM;ei~XC$;2j#=8t%V&V}G!}kB!9% zV?sY^-(a=xBOOz57PO02t$&S!DPdWQSs`^QHcoP%Hyny1H}*n+A>FD>+PTM$gEXtSb1|elx`JxlEMG6* zSYsHHvpb&_tBnHhq30U>9F(`px68qfI$8ip$9QwvVWNXFI0`uLE6L)lS^fCvXM(U{ zi=Guv&3R_hJq>Bm0liNcl@sP5ItIrxJa~eRL2e*pSpB|=eSC0mjF$Tu1_!ZhVp@3H z3SkegluUHY(WN6i&+^}SDX%KL!9fAkBe+-b9a|BiVfFx72JV<-B6AqXh>HF!3iv3h=h2WK3%z`w##C zUbg!2gq$SRp>w`LLRHSIvvYDFM7x$P$#^YWIlH{k;PC>pp4}5=>li^W(Y9m+RB!;h z)L4iVlNS-g6oL}2sB+0xz@$}g@N(_@$|1X+76MnYkjFk;YCWYX9Q0tW zvRtuZqXpMxtGN!OMS=p+#9ZWc2pm7S!(S(<)l#u1OBEpZT$#v$So>I@5j}CT7;RAf OphBT|KQ2%>(EkVF*, 2017. +# +msgid "" +msgstr "" +"Project-Id-Version: DSMR Reader 1.x\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-02-19 18:05+0100\n" +"PO-Revision-Date: 2017-02-19 18:15+0100\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.3.4\n" +"Language: nl\n" +"X-Generator: Poedit 1.8.7.1\n" + +#: ../../troubleshooting.rst:2 +msgid "Troubleshooting" +msgstr "Hulp bij problemen" + +#: ../../troubleshooting.rst:3 +msgid "" +"If the application happens to stall unexpectedly, you can perform some " +"debugging on your end." +msgstr "" +"Mocht de applicatie onverwachts stoppen, dan kun je zelf het volgende " +"doen om te kijken of je een oorzaak kan vinden." + +#: ../../troubleshooting.rst:6 +msgid "Status page" +msgstr "Status-pagina" + +#: ../../troubleshooting.rst:7 +msgid "" +"The first place to look at is the Status page in the application. Does " +"it display any error or is it lagging data processing?" +msgstr "" +"Als eerste kun je het beste naar de Status-pagina gaan. Staat daar een " +"foutmelding of loopt de dataverwerking achter?" + +#: ../../troubleshooting.rst:13 +msgid "Supervisor" +msgstr "Supervisor" + +#: ../../troubleshooting.rst:14 +msgid "" +"You can also view the Supervisor logfiles, depending on whether your " +"datalogger, webinterface or the data processing is broken. The logfiles " +"are located by default in ``/var/log/supervisor/``. You should find logs " +"here regarding the ``dsmr_datalogger``, ``dsmr_backend`` and " +"``dsmr_webinterface`` processes." +msgstr "" +"Je kunt ook de Supervisor-logfiles bekijken, afhankelijk van of je " +"datalogger, webinterface of dataverwerking gestopt is. De logfiles staan " +"standaard in ``/var/log/supervisor/``. Je vindt hier logfiles voor de " +"``dsmr_datalogger``, ``dsmr_backend`` en ``dsmr_webinterface`` processen." + +#: ../../troubleshooting.rst:18 +msgid "" +"Another option is to tail the (recent) logs in Supervisor. Enter the " +"control panel with ``sudo supervisorctl`` and type ``tail -f " +"PROCESSNAME`` to follow one. The process names are the ones you see when " +"you started the control panel, or you can just enter ``status`` to see " +"them. You can also use ``start``, ``stop`` or ``restart`` on the " +"processes to give control them." +msgstr "" +"Eventueel kun je ook de (recente) logfiles direct in Supervisor " +"bekijken. Ga naar het beheerpaneel met ``sudo supervisorctl`` en typ " +"``tail -f PROCESNAAM`` om er een te volgen. De procesnamen zijn degene " +"die je ziet wanneer je het beheerpaneel opende. Je kunt ook ``status`` " +"typen om ze allemaal te weergeven. Gebruik ``start``, ``stop`` of " +"``restart`` om de processen verder te beheren." + +#: ../../troubleshooting.rst:26 +msgid "Appplication / Django" +msgstr "Appplicatie / Django" + +#: ../../troubleshooting.rst:27 +msgid "" +"The application has it's own logfiles as well. You can find them in the " +"``logs`` directory inside the project folder. The ``django.log`` will " +"list any internal errors regarding the Django framework it's using. The " +"other logfile ``dsmrreader.log`` contains all readings it received, in " +"base64 format." +msgstr "" +"De applicatie heeft zelf ook logfiles. Deze vindt je in de ``logs`` " +"directory binnenin het project. De ``django.log`` bevat alle interne " +"fouten m.b.t. het gebruikte Django framework. De andere logfile, " +"``dsmrreader.log`` bevat doorgaans alle ontvangen metingen, in base64-" +"formaat." + +#: ../../troubleshooting.rst:35 +msgid "Contact" +msgstr "Contact" + +#: ../../troubleshooting.rst:36 +msgid "" +"Are you unable to resolve your problem or do you need any help? :doc:" +"`More information can be found here`." +msgstr "" +"Kom je er toch niet uit of heb je hulp nodig? :doc:`Meer informatie kun " +"je hier vinden`." diff --git a/docs/screenshots.rst b/docs/screenshots.rst index d82f277cf..e3cff7ab7 100644 --- a/docs/screenshots.rst +++ b/docs/screenshots.rst @@ -7,16 +7,6 @@ Below you can find some screenshots of the application. Please read the note bel :depth: 2 -Solar panels & electricity returned ------------------------------------ - -.. note:: - - Note that **I do not have solar panels at home**, but the application however **does support plotting any electricity returned**. - -Therefor there aren't always graphs of them in the screenshots, but the users who do have them, will have additional green graphs rendered in the application. - - Dashboard --------- The dashboard displays the latest information regarding any consumption of today and the current month so far. diff --git a/docs/settings.rst b/docs/settings.rst new file mode 100644 index 000000000..c5f3d785d --- /dev/null +++ b/docs/settings.rst @@ -0,0 +1,181 @@ +Settings +======== + +The application has several settings available, which you can edit in the Configuration page. +The default settings should work fine, although it's recommended to enable syncing backups using Dropbox. + +.. contents:: + + +Database/Django settings +------------------------ +``dsmrreader/settings.py`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ +In case you want to alter the database settings, or any other Django settings, please modify (or add) them to the ``dsmrreader/settings.py`` file. + +Make sure to reload the application afterwards to persist the changes you've made, by executing ``./reload.sh`` or restarting the Supervisor processes. + + +API configuration +----------------- + +The application does have an API, but it's disabled by default. +You can enable it by activating the "Allow API calls" option. + +``Allow API calls`` +~~~~~~~~~~~~~~~~~~~ +Whether the API is enabled. + +``Auth Key`` +~~~~~~~~~~~~ +The auth key used for authentication. + + + +Backup configuration +-------------------- +The application creates a daily database backup by default. +You choose whether you want to have it compressed or in raw SQL form. +The timestamp of the backup can be altered as well. + +``Backup daily`` +~~~~~~~~~~~~~~~~ +Whether to created backups at all. + +``Compress`` +~~~~~~~~~~~~ +Enable this to have the backups compressed in gzip format. +Highly recommended as it will make backups up to 10 times smaller! + +``Backup timestamp`` +~~~~~~~~~~~~~~~~~~~~ +Timestamp of the daily backup. + + + +Dropbox configuration +--------------------- +There is a Dropbox integration available to safely transfer each daily backup into your Dropbox account. +:doc:`More information about this feature can be found in the FAQ`. + +``Dropbox access token`` +~~~~~~~~~~~~~~~~~~~~~~~~ +Enter your Dropbox access token here. Leave blank or clear to disable Dropbox integration. + + + +Consumption configuration +------------------------- +The consumption settings determine how the application should handle the separate readings. +The default behaviour is to group all readings each minute. This can be disabled. + +``Compactor grouping type`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The density of the readings, visible in the application as consumption. + + + +Energy supplier prices +---------------------- +You can enter all your energy contract prices here. +The application will use them (when available) to calculate the consumption of each day. +:doc:`See the FAQ on how to retroactivily adjust prices (if needed)`. + + + +Datalogger configuration +------------------------ +This configuration applies to how to read your smart meter. + +``Poll P1 port`` +~~~~~~~~~~~~~~~~ +Do not disable this. Will be removed next release. + +``Track electricity phases`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Whether you want to track phases. +:doc:`More information about this feature can be found in the FAQ`. + +``Verify telegram CRC`` +~~~~~~~~~~~~~~~~~~~~~~~ +Whether the application should verify the incoming data. Only available for DSMR 4+. + +``DSMR version`` +~~~~~~~~~~~~~~~~ +The DSMR version your smart meter has. Used to determine how the serial connection should work. + +``COM-port`` +~~~~~~~~~~~~ +The COM port your cable can be read from. + + + +Frontend configuration +---------------------- +This applies to the visualisation in the application. + +``Merge electricity tariffs`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Whether to merge the high and low tariffs. +:doc:`More information about this feature can be found in the FAQ`. + +``**** color`` +~~~~~~~~~~~~~~ +Multiple colors can be set here for the graphs. + + + +MinderGas.nl configuration +-------------------------- +Optional connection with your account at MinderGas.nl. +:doc:`More information about this feature can be found in the FAQ`. + + +``Export data to MinderGas`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Whether to enable the connecting with MinderGas. + +``MinderGas authentication token`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +API token for your MinderGas.nl account. + + + +Notes +----- +You can leave personal notes for yourself here. +Such as when you were on holiday or experimented with the heater settings. + + + +Notification configuration +-------------------------- +Allows sending daily notifications to your phone. +:doc:`More information about this feature can be found in the FAQ`. + +``Send notification`` +~~~~~~~~~~~~~~~~~~~~~ +Whether to enable this feature. + +``Notification service`` +~~~~~~~~~~~~~~~~~~~~~~~~ +The notification service you are using. + +``Notification service API key`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +API token for your account of the notification service. + + +Weather configuration +--------------------- +There is support for tracking outside temperatures for a fixed number of weather stations. +:doc:`More information about this feature can be found in the FAQ`. + +``Track weather`` +~~~~~~~~~~~~~~~~~ +Whether to enable this feature. + +``Buienradar weather station`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The fixed weather station you wish to use. + diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst new file mode 100644 index 000000000..53151b3b9 --- /dev/null +++ b/docs/troubleshooting.rst @@ -0,0 +1,37 @@ +Troubleshooting +=============== +If the application happens to stall unexpectedly, you can perform some debugging on your end. + +Status page +----------- +The first place to look at is the Status page in the application. +Does it display any error or is it lagging data processing? + + + +Supervisor +---------- +You can also view the Supervisor logfiles, depending on whether your datalogger, webinterface or the data processing is broken. +The logfiles are located by default in ``/var/log/supervisor/``. +You should find logs here regarding the ``dsmr_datalogger``, ``dsmr_backend`` and ``dsmr_webinterface`` processes. + +Another option is to tail the (recent) logs in Supervisor. +Enter the control panel with ``sudo supervisorctl`` and type ``tail -f PROCESSNAME`` to follow one. +The process names are the ones you see when you started the control panel, or you can just enter ``status`` to see them. +You can also use ``start``, ``stop`` or ``restart`` on the processes to give control them. + + + +Appplication / Django +--------------------- +The application has it's own logfiles as well. +You can find them in the ``logs`` directory inside the project folder. +The ``django.log`` will list any internal errors regarding the Django framework it's using. +The other logfile ``dsmrreader.log`` contains all readings it received, in base64 format. + + + +Contact +------- +Are you unable to resolve your problem or do you need any help? +:doc:`More information can be found here`. diff --git a/dsmr_api/tests/test_api.py b/dsmr_api/tests/test_api.py index e68a63318..af9d9a3ed 100644 --- a/dsmr_api/tests/test_api.py +++ b/dsmr_api/tests/test_api.py @@ -113,5 +113,5 @@ def test_okay(self, verify_telegram_checksum_mock): # Disable CRC for this test, as it's tested elsewhere. But verify that it was called anyway. self.assertTrue(verify_telegram_checksum_mock.called) self.assertTrue(DsmrReading.objects.exists()) - self.assertEqual(response.status_code, 200) + self.assertEqual(response.status_code, 201) self.assertEqual(response.content, b'') diff --git a/dsmr_api/views.py b/dsmr_api/views.py index d1571bc37..53a86a2ab 100644 --- a/dsmr_api/views.py +++ b/dsmr_api/views.py @@ -18,17 +18,14 @@ class DataloggerDsmrReading(View): def post(self, request): api_settings = APISettings.get_solo() - # API disabled. if not api_settings.allow: return HttpResponseNotAllowed(permitted_methods=['POST'], content=_('API is disabled')) - # Auth key mismatch. if request.META.get('HTTP_X_AUTHKEY') != api_settings.auth_key: return HttpResponseForbidden(content=_('Invalid auth key')) post_form = DsmrReadingForm(request.POST) - # Data omitted. if not post_form.is_valid(): logger.warning('API validation failed with POST data: {}'.format(request.POST)) return HttpResponseBadRequest(_('Invalid data')) @@ -41,8 +38,7 @@ def post(self, request): # The service called already logs the error. pass - # Data invalid. if not dsmr_reading: return HttpResponseServerError(content=_('Failed to parse telegram')) - return HttpResponse() + return HttpResponse(status=201) diff --git a/dsmr_backend/apps.py b/dsmr_backend/apps.py index be937004f..cca224669 100644 --- a/dsmr_backend/apps.py +++ b/dsmr_backend/apps.py @@ -13,7 +13,7 @@ class AppConfig(AppConfig): def ready(self): """ Performs an DB engine check, as we maintain some engine specific queries. """ - if (connection.vendor not in settings.DSMR_SUPPORTED_DB_VENDORS): # pragma: no cover + if (connection.vendor not in settings.DSMRREADER_SUPPORTED_DB_VENDORS): # pragma: no cover # Temporary for backwards compatibility warnings.showwarning( _( diff --git a/dsmr_backend/management/commands/development_reset.py b/dsmr_backend/management/commands/development_reset.py new file mode 100644 index 000000000..efcfb42fb --- /dev/null +++ b/dsmr_backend/management/commands/development_reset.py @@ -0,0 +1,21 @@ +from django.core.management.base import BaseCommand, CommandError +from django.utils.translation import ugettext as _ +from django.conf import settings + +from dsmr_backup.models.settings import BackupSettings, DropboxSettings +from dsmr_mindergas.models.settings import MinderGasSettings +from dsmr_notification.models.settings import NotificationSetting + + +class Command(BaseCommand): + help = _('Resets the environment for development purposes. Not intended for production.') + + def handle(self, **options): + if not settings.DEBUG: + raise CommandError(_('Intended usage is NOT production! Only allowed when DEBUG = True')) + + # Just wipe all settings which can affect the environment. + BackupSettings.objects.update(daily_backup=False) + DropboxSettings.objects.update(access_token=None) + MinderGasSettings.objects.update(export=False, auth_token=None) + NotificationSetting.objects.update(send_notification=False, api_key=None) diff --git a/dsmr_backend/management/commands/dsmr_backend.py b/dsmr_backend/management/commands/dsmr_backend.py index 991e9a362..f9a330369 100644 --- a/dsmr_backend/management/commands/dsmr_backend.py +++ b/dsmr_backend/management/commands/dsmr_backend.py @@ -1,7 +1,7 @@ import traceback from raven.contrib.django.raven_compat.models import client as raven_client -from django.core.management.base import BaseCommand, CommandError +from django.core.management.base import BaseCommand from django.utils.translation import ugettext as _ from django.utils import timezone @@ -38,7 +38,3 @@ def run(self, **options): self.stdout.write(' >>> {} :: {}'.format(current_receiver, exception_traceback)) self.stderr.write(exception_traceback) signal_failures.append(exception_traceback) - - if signal_failures: - # Reflect any error to output for convenience. - raise CommandError(signal_failures) diff --git a/dsmr_backend/mixins.py b/dsmr_backend/mixins.py index 5e8921495..c58b49699 100644 --- a/dsmr_backend/mixins.py +++ b/dsmr_backend/mixins.py @@ -29,7 +29,7 @@ def __del__(self): def _write_pid_file(self): self._pid_file = os.path.join( - settings.DSMR_MANAGEMENT_COMMANDS_PID_FOLDER, + settings.DSMRREADER_MANAGEMENT_COMMANDS_PID_FOLDER, 'dsmrreader--{}.pid'.format(self.name.split('.')[-1]) # Set in management command. ) with open(self._pid_file, 'w') as file_handle: @@ -55,7 +55,7 @@ def handle(self, **options): # We simply keep executing the management command until we are told otherwise. self._keep_alive = True - print('Starting INFINITE command loop...') # Just to make sure it gets printed. + print('Starting infinite command loop...') # Just to make sure it gets printed. while self._keep_alive: self.run(**options) diff --git a/dsmr_backend/services.py b/dsmr_backend/services.py index 478f2ca4b..64035a0e3 100644 --- a/dsmr_backend/services.py +++ b/dsmr_backend/services.py @@ -43,9 +43,9 @@ def get_capabilities(capability=None): def is_latest_version(): """ Checks whether the current version is the latest one available on Github. """ - response = requests.get(settings.DSMR_LATEST_VERSION_FILE) + response = requests.get(settings.DSMRREADER_LATEST_VERSION_FILE) - local_version = '{}.{}.{}'.format(* settings.DSMR_RAW_VERSION[:3]) + local_version = '{}.{}.{}'.format(* settings.DSMRREADER_RAW_VERSION[:3]) remote_version = re.search(r'^VERSION = \((\d+), (\d+), (\d+),', str(response.content, 'utf-8'), flags=re.MULTILINE) remote_version = '.'.join(remote_version.groups()) diff --git a/dsmr_backend/tests/test_backend.py b/dsmr_backend/tests/test_backend.py index 9ee7099bb..f8b55b10b 100644 --- a/dsmr_backend/tests/test_backend.py +++ b/dsmr_backend/tests/test_backend.py @@ -1,6 +1,5 @@ from unittest import mock -from django.core.management import CommandError from django.test import TestCase from django.conf import settings @@ -41,10 +40,6 @@ def _fake_signal_troublemaker(*args, **kwargs): dsmr_backend.signals.backend_called.connect(receiver=_fake_signal_troublemaker) - with self.assertRaises(CommandError): - # Signal should crash, rasing a command error. - self._intercept_command_stdout('dsmr_backend') - # We must disconnect to prevent other tests from failing, since this is no database action. dsmr_backend.signals.backend_called.disconnect(receiver=_fake_signal_troublemaker) @@ -58,16 +53,13 @@ def _fake_signal_troublemaker(*args, **kwargs): dsmr_backend.signals.backend_called.connect(receiver=_fake_signal_troublemaker) self.assertFalse(raven_mock.called) - with self.assertRaises(CommandError): - # Signal should crash, rasing a command error. - self._intercept_command_stdout('dsmr_backend') - + self._intercept_command_stdout('dsmr_backend') self.assertTrue(raven_mock.called) def test_supported_vendors(self): """ Check whether supported vendors is as expected. """ self.assertEqual( - settings.DSMR_SUPPORTED_DB_VENDORS, + settings.DSMRREADER_SUPPORTED_DB_VENDORS, ('postgresql', 'mysql') ) diff --git a/dsmr_backup/admin.py b/dsmr_backup/admin.py index 6ef7a38a3..defeb1143 100644 --- a/dsmr_backup/admin.py +++ b/dsmr_backup/admin.py @@ -1,6 +1,7 @@ from django.contrib import admin from django.forms import TextInput from django.db import models +from django.utils.translation import ugettext_lazy as _ from solo.admin import SingletonModelAdmin from .models.settings import BackupSettings, DropboxSettings @@ -10,6 +11,17 @@ class BackupSettingsAdmin(SingletonModelAdmin): list_display = ('daily_backup', 'compress', 'backup_time') readonly_fields = ('latest_backup', ) + fieldsets = ( + ( + None, { + 'fields': ['daily_backup', 'compress', 'backup_time', 'latest_backup'], + 'description': _( + 'Detailed instructions for restoring a backup can be found here: FAQ in documentation' + ) + } + ), + ) @admin.register(DropboxSettings) @@ -19,3 +31,14 @@ class DropboxSettingsAdmin(SingletonModelAdmin): formfield_overrides = { models.CharField: {'widget': TextInput(attrs={'size': '64'})}, } + fieldsets = ( + ( + None, { + 'fields': ['access_token', 'latest_sync'], + 'description': _( + 'Detailed instructions for configuring Dropbox can be found here: FAQ in documentation' + ) + } + ), + ) diff --git a/dsmr_backup/migrations/0002_settings_documentation.py b/dsmr_backup/migrations/0002_settings_documentation.py new file mode 100644 index 000000000..47a9b1ae1 --- /dev/null +++ b/dsmr_backup/migrations/0002_settings_documentation.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-02-19 17:20 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dsmr_backup', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='dropboxsettings', + name='access_token', + field=models.CharField(blank=True, default=None, max_length=128, null=True, verbose_name='Dropbox access token'), + ), + ] diff --git a/dsmr_backup/models/settings.py b/dsmr_backup/models/settings.py index fee380bb2..7271dc1b7 100644 --- a/dsmr_backup/models/settings.py +++ b/dsmr_backup/models/settings.py @@ -52,14 +52,6 @@ class DropboxSettings(SingletonModel): null=True, blank=True, verbose_name=_('Dropbox access token'), - help_text=_( - 'The access token for your Dropbox account. You should register an App for your own ' - 'Dropbox account (https://www.dropbox.com/developers/apps). Please select "Permission ' - 'type" named "App folder" to restrict unneeded access. Backups will be synced to a ' - 'dedicated folder in your account. After creating your App you should be able to ' - 'generate an "Access token" and enter it here. For more information, see https://' - 'blogs.dropbox.com/developers/2014/05/generate-an-access-token-for-your-own-account' - ) ) latest_sync = models.DateTimeField( diff --git a/dsmr_backup/services/backup.py b/dsmr_backup/services/backup.py index 73d49e3f4..f14a40bbf 100644 --- a/dsmr_backup/services/backup.py +++ b/dsmr_backup/services/backup.py @@ -41,7 +41,7 @@ def check(): def get_backup_directory(): """ Returns the path to the directory where all backups are stored locally. """ - return os.path.join(settings.BASE_DIR, '..', settings.DSMR_BACKUP_DIRECTORY) + return os.path.join(settings.BASE_DIR, '..', settings.DSMRREADER_BACKUP_DIRECTORY) def create(): diff --git a/dsmr_backup/services/dropbox.py b/dsmr_backup/services/dropbox.py index 99aa0e056..c49c32574 100644 --- a/dsmr_backup/services/dropbox.py +++ b/dsmr_backup/services/dropbox.py @@ -20,7 +20,7 @@ def sync(): if dropbox_settings.latest_sync: next_sync_interval = dropbox_settings.latest_sync + timezone.timedelta( - hours=settings.DSMR_DROPBOX_SYNC_INTERVAL + hours=settings.DSMRREADER_DROPBOX_SYNC_INTERVAL ) if next_sync_interval and timezone.now() < next_sync_interval: diff --git a/dsmr_backup/tests/test_services.py b/dsmr_backup/tests/test_services.py index 97d2bda37..2a8f16b09 100644 --- a/dsmr_backup/tests/test_services.py +++ b/dsmr_backup/tests/test_services.py @@ -92,7 +92,7 @@ def test_check_backup_time_restriction(self, now_mock, create_backup_mock): def test_get_backup_directory(self): self.assertEqual( dsmr_backup.services.backup.get_backup_directory(), - os.path.join(settings.BASE_DIR, '..', settings.DSMR_BACKUP_DIRECTORY) + os.path.join(settings.BASE_DIR, '..', settings.DSMRREADER_BACKUP_DIRECTORY) ) @mock.patch('subprocess.Popen') diff --git a/dsmr_consumption/admin.py b/dsmr_consumption/admin.py index ada041362..663cef77e 100644 --- a/dsmr_consumption/admin.py +++ b/dsmr_consumption/admin.py @@ -1,8 +1,10 @@ from django.contrib import admin from solo.admin import SingletonModelAdmin -from .models.settings import ConsumptionSettings +from dsmr_backend.mixins import ReadOnlyAdminModel +from .models.consumption import ElectricityConsumption, GasConsumption from .models.energysupplier import EnergySupplierPrice +from .models.settings import ConsumptionSettings @admin.register(ConsumptionSettings) @@ -13,3 +15,13 @@ class ConsumptionSettingsAdmin(SingletonModelAdmin): @admin.register(EnergySupplierPrice) class EnergySupplierPriceAdmin(admin.ModelAdmin): list_display = ('description', 'start', 'end') + + +@admin.register(ElectricityConsumption) +class ElectricityConsumptionAdmin(ReadOnlyAdminModel): + list_display = ('read_at', 'currently_delivered', 'currently_returned') + + +@admin.register(GasConsumption) +class GasConsumptionAdmin(ReadOnlyAdminModel): + list_display = ('read_at', 'currently_delivered') diff --git a/dsmr_consumption/fixtures/dsmr_consumption/test_dsmrreading_v5.json b/dsmr_consumption/fixtures/dsmr_consumption/test_dsmrreading_v5.json new file mode 100644 index 000000000..1dda4f0c9 --- /dev/null +++ b/dsmr_consumption/fixtures/dsmr_consumption/test_dsmrreading_v5.json @@ -0,0 +1,107 @@ +[ +{ + "fields": { + "extra_device_timestamp": "2015-11-10T19:00:00Z", + "extra_device_delivered": "1.00", + "electricity_delivered_1": "528.750", + "electricity_returned_2": "123.456", + "electricity_currently_delivered": "0.247", + "timestamp": "2015-11-10T19:40:47Z", + "electricity_returned_1": "0.456", + "electricity_currently_returned": "0.123", + "processed": false, + "electricity_delivered_2": "525.500" + }, + "model": "dsmr_datalogger.dsmrreading", + "pk": 99 +}, +{ + "fields": { + "extra_device_timestamp": "2015-11-10T19:01:05Z", + "extra_device_delivered": "1.05", + "electricity_delivered_1": "528.750", + "electricity_returned_2": "123.456", + "electricity_currently_delivered": "0.247", + "timestamp": "2015-11-10T19:40:47Z", + "electricity_returned_1": "0.456", + "electricity_currently_returned": "0.123", + "processed": false, + "electricity_delivered_2": "525.500" + }, + "model": "dsmr_datalogger.dsmrreading", + "pk": 100 +}, +{ + "fields": { + "extra_device_timestamp": "2015-11-10T19:01:10Z", + "extra_device_delivered": "1.06", + "electricity_delivered_1": "529.750", + "electricity_returned_2": "123.567", + "electricity_currently_delivered": "0.750", + "timestamp": "2015-11-10T19:40:57Z", + "electricity_returned_1": "0.567", + "electricity_currently_returned": "0.123", + "processed": false, + "electricity_delivered_2": "527.500" + }, + "model": "dsmr_datalogger.dsmrreading", + "pk": 101 +}, +{ + "fields": { + "extra_device_timestamp": "2015-11-10T19:01:30Z", + "extra_device_delivered": "1.07", + "electricity_delivered_1": "530.750", + "electricity_returned_2": "123.678", + "electricity_currently_delivered": "1.123", + "timestamp": "2015-11-10T19:41:07Z", + "electricity_returned_1": "0.678", + "electricity_currently_returned": "0.123", + "processed": false, + "electricity_delivered_2": "528.500", + "phase_currently_delivered_l1": "0.123", + "phase_currently_delivered_l2": "0.456", + "phase_currently_delivered_l3": "0.789" + }, + "model": "dsmr_datalogger.dsmrreading", + "pk": 102 +}, +{ + "fields": { + "extra_device_timestamp": "2015-11-10T19:02:30Z", + "extra_device_delivered": "1.08", + "electricity_delivered_1": "530.750", + "electricity_returned_2": "123.678", + "electricity_currently_delivered": "1.123", + "timestamp": "2015-11-10T19:41:07Z", + "electricity_returned_1": "0.678", + "electricity_currently_returned": "0.123", + "processed": false, + "electricity_delivered_2": "528.500", + "phase_currently_delivered_l1": "0.123", + "phase_currently_delivered_l2": "0.456", + "phase_currently_delivered_l3": "0.789" + }, + "model": "dsmr_datalogger.dsmrreading", + "pk": 103 +}, +{ + "fields": { + "extra_device_timestamp": "2015-11-10T20:02:30Z", + "extra_device_delivered": "1.15", + "electricity_delivered_1": "530.750", + "electricity_returned_2": "123.678", + "electricity_currently_delivered": "1.123", + "timestamp": "2015-11-10T19:41:07Z", + "electricity_returned_1": "0.678", + "electricity_currently_returned": "0.123", + "processed": false, + "electricity_delivered_2": "528.500", + "phase_currently_delivered_l1": "0.123", + "phase_currently_delivered_l2": "0.456", + "phase_currently_delivered_l3": "0.789" + }, + "model": "dsmr_datalogger.dsmrreading", + "pk": 104 +} +] \ No newline at end of file diff --git a/dsmr_consumption/migrations/0006_dsmr_firmware_v5.py b/dsmr_consumption/migrations/0006_dsmr_firmware_v5.py new file mode 100644 index 000000000..82b0cbbd6 --- /dev/null +++ b/dsmr_consumption/migrations/0006_dsmr_firmware_v5.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.4 on 2017-01-26 20:30 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dsmr_consumption', '0005_phase_currently_delivered'), + ] + + operations = [ + migrations.AlterModelOptions( + name='electricityconsumption', + options={'default_permissions': (), 'verbose_name': 'Electricity consumption'}, + ), + migrations.AlterModelOptions( + name='gasconsumption', + options={'default_permissions': (), 'verbose_name': 'Gas consumption'}, + ), + migrations.AlterField( + model_name='gasconsumption', + name='currently_delivered', + field=models.DecimalField(decimal_places=3, help_text='Delivered value, based on the previous reading', max_digits=9), + ), + migrations.AlterField( + model_name='gasconsumption', + name='delivered', + field=models.DecimalField(decimal_places=3, help_text='Last meter position read', max_digits=9), + ), + ] diff --git a/dsmr_consumption/migrations/0007_settings_documentation.py b/dsmr_consumption/migrations/0007_settings_documentation.py new file mode 100644 index 000000000..927a3af09 --- /dev/null +++ b/dsmr_consumption/migrations/0007_settings_documentation.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.5 on 2017-02-19 17:20 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('dsmr_consumption', '0006_dsmr_firmware_v5'), + ] + + operations = [ + migrations.AlterModelOptions( + name='electricityconsumption', + options={'default_permissions': (), 'verbose_name': 'Electricity consumption', 'verbose_name_plural': 'Electricity consumption'}, + ), + migrations.AlterModelOptions( + name='gasconsumption', + options={'default_permissions': (), 'verbose_name': 'Gas consumption', 'verbose_name_plural': 'Gas consumption'}, + ), + ] diff --git a/dsmr_consumption/models/consumption.py b/dsmr_consumption/models/consumption.py index 599fd4d5c..280d53e73 100644 --- a/dsmr_consumption/models/consumption.py +++ b/dsmr_consumption/models/consumption.py @@ -69,21 +69,23 @@ def __str__(self): class Meta: default_permissions = tuple() + verbose_name = _('Electricity consumption') + verbose_name_plural = verbose_name class GasConsumption(models.Model): - """ Hourly consumption (usage), interpolated on the previous value read the hour before. """ + """ Interpolated gas reading, containing the actualy usage, based on the reading before (if any). """ read_at = models.DateTimeField(unique=True) delivered = models.DecimalField( max_digits=9, decimal_places=3, - help_text=_("Last hourly value delivered to client") + help_text=_("Last meter position read") ) # This value is not provided by DSMR so we calculate the difference relative to the previous reading. currently_delivered = models.DecimalField( max_digits=9, decimal_places=3, - help_text=_("Actual value delivered to client, since the last hour") + help_text=_("Delivered value, based on the previous reading") ) def __str__(self): @@ -93,3 +95,5 @@ def __str__(self): class Meta: default_permissions = tuple() + verbose_name = _('Gas consumption') + verbose_name_plural = verbose_name diff --git a/dsmr_consumption/services.py b/dsmr_consumption/services.py index 062e5e7ff..c3b240bbd 100644 --- a/dsmr_consumption/services.py +++ b/dsmr_consumption/services.py @@ -11,13 +11,12 @@ from dsmr_datalogger.models.reading import DsmrReading from dsmr_weather.models.reading import TemperatureReading from dsmr_stats.models.note import Note +from dsmr_datalogger.models.statistics import MeterStatistics def compact_all(): """ Compacts all unprocessed readings, capped by a max to prevent hanging backend. """ - unprocessed_readings = DsmrReading.objects.unprocessed()[0:1000] - - for current_reading in unprocessed_readings: + for current_reading in DsmrReading.objects.unprocessed()[0:128]: compact(dsmr_reading=current_reading) @@ -27,6 +26,32 @@ def compact(dsmr_reading): """ grouping_type = ConsumptionSettings.get_solo().compactor_grouping_type + # Grouping by minute requires some distinction and history checking. + reading_start = timezone.datetime.combine( + dsmr_reading.timestamp.date(), + time(hour=dsmr_reading.timestamp.hour, minute=dsmr_reading.timestamp.minute), + ).replace(tzinfo=pytz.UTC) + + if grouping_type == ConsumptionSettings.COMPACTOR_GROUPING_BY_MINUTE: + # Postpone when current minute hasn't passed yet. + if timezone.now() <= reading_start + timezone.timedelta(minutes=1): + return + + # Create consumption records. + _compact_electricity(dsmr_reading=dsmr_reading, grouping_type=grouping_type, reading_start=reading_start) + _compact_gas(dsmr_reading=dsmr_reading, grouping_type=grouping_type, reading_start=reading_start) + + dsmr_reading.processed = True + dsmr_reading.save(update_fields=['processed']) + + # For backend logging in Supervisor. + print(' - Processed reading: {}'.format(dsmr_reading)) + + +def _compact_electricity(dsmr_reading, grouping_type, reading_start): + """ + Compacts any DSMR readings to electricity consumption records, optionally grouped. + """ # Electricity should be unique, because it's the reading with the lowest interval anyway. if grouping_type == ConsumptionSettings.COMPACTOR_GROUPING_BY_READING: ElectricityConsumption.objects.get_or_create( @@ -41,79 +66,84 @@ def compact(dsmr_reading): phase_currently_delivered_l2=dsmr_reading.phase_currently_delivered_l2, phase_currently_delivered_l3=dsmr_reading.phase_currently_delivered_l3, ) - # Grouping by minute requires some distinction and history checking. - else: - minute_start = timezone.datetime.combine( - dsmr_reading.timestamp.date(), - time(hour=dsmr_reading.timestamp.hour, minute=dsmr_reading.timestamp.minute), - ).replace(tzinfo=pytz.UTC) - minute_end = minute_start + timezone.timedelta(minutes=1) + return - # Postpone when current minute hasn't passed yet. - if timezone.now() <= minute_end: - return + minute_end = reading_start + timezone.timedelta(minutes=1) - # We might have six readings per minute, so there is a chance we already parsed it. - if not ElectricityConsumption.objects.filter(read_at=minute_end).exists(): - grouped_reading = DsmrReading.objects.filter( - timestamp__gte=minute_start, timestamp__lt=minute_end - ).aggregate( - avg_delivered=Avg('electricity_currently_delivered'), - avg_returned=Avg('electricity_currently_returned'), - max_delivered_1=Max('electricity_delivered_1'), - max_delivered_2=Max('electricity_delivered_2'), - max_returned_1=Max('electricity_returned_1'), - max_returned_2=Max('electricity_returned_2'), - avg_phase_delivered_l1=Avg('phase_currently_delivered_l1'), - avg_phase_delivered_l2=Avg('phase_currently_delivered_l2'), - avg_phase_delivered_l3=Avg('phase_currently_delivered_l3'), - ) - - # This instance is the average/max and combined result. - ElectricityConsumption.objects.create( - read_at=minute_end, - delivered_1=grouped_reading['max_delivered_1'], - returned_1=grouped_reading['max_returned_1'], - delivered_2=grouped_reading['max_delivered_2'], - returned_2=grouped_reading['max_returned_2'], - currently_delivered=grouped_reading['avg_delivered'], - currently_returned=grouped_reading['avg_returned'], - phase_currently_delivered_l1=grouped_reading['avg_phase_delivered_l1'], - phase_currently_delivered_l2=grouped_reading['avg_phase_delivered_l2'], - phase_currently_delivered_l3=grouped_reading['avg_phase_delivered_l3'], - ) - - # Gas is optional. - if dsmr_reading.extra_device_timestamp and dsmr_reading.extra_device_delivered: - # Gas however is only read (or updated) once every hour, so we should check for any duplicates - # as they will exist at some point. - passed_hour_start = dsmr_reading.extra_device_timestamp - timezone.timedelta(hours=1) - - if not GasConsumption.objects.filter(read_at=passed_hour_start).exists(): - # DSMR does not expose current gas rate, so we have to calculate - # it ourselves, relative to the previous gas consumption, if any. - try: - previous_gas_consumption = GasConsumption.objects.get( - # Compare to reading before, if any. - read_at=passed_hour_start - timezone.timedelta(hours=1) - ) - except GasConsumption.DoesNotExist: - gas_diff = 0 - else: - gas_diff = dsmr_reading.extra_device_delivered - previous_gas_consumption.delivered - - GasConsumption.objects.create( - # Gas consumption is aligned to start of the hour. - read_at=passed_hour_start, - delivered=dsmr_reading.extra_device_delivered, - currently_delivered=gas_diff - ) + # We might have multiple readings per minute, so there is a chance we already parsed it a moment ago. + if ElectricityConsumption.objects.filter(read_at=minute_end).exists(): + return - dsmr_reading.processed = True - dsmr_reading.save(update_fields=['processed']) + grouped_reading = DsmrReading.objects.filter( + timestamp__gte=reading_start, timestamp__lt=minute_end + ).aggregate( + avg_delivered=Avg('electricity_currently_delivered'), + avg_returned=Avg('electricity_currently_returned'), + max_delivered_1=Max('electricity_delivered_1'), + max_delivered_2=Max('electricity_delivered_2'), + max_returned_1=Max('electricity_returned_1'), + max_returned_2=Max('electricity_returned_2'), + avg_phase_delivered_l1=Avg('phase_currently_delivered_l1'), + avg_phase_delivered_l2=Avg('phase_currently_delivered_l2'), + avg_phase_delivered_l3=Avg('phase_currently_delivered_l3'), + ) - # For backend logging in Supervisor. - print(' - Processed reading: {}.'.format(timezone.localtime(dsmr_reading.timestamp))) + # This instance is the average/max and combined result. + ElectricityConsumption.objects.create( + read_at=minute_end, + delivered_1=grouped_reading['max_delivered_1'], + returned_1=grouped_reading['max_returned_1'], + delivered_2=grouped_reading['max_delivered_2'], + returned_2=grouped_reading['max_returned_2'], + currently_delivered=grouped_reading['avg_delivered'], + currently_returned=grouped_reading['avg_returned'], + phase_currently_delivered_l1=grouped_reading['avg_phase_delivered_l1'], + phase_currently_delivered_l2=grouped_reading['avg_phase_delivered_l2'], + phase_currently_delivered_l3=grouped_reading['avg_phase_delivered_l3'], + ) + + +def _compact_gas(dsmr_reading, grouping_type, **kwargs): + """ + Compacts any DSMR readings to gas consumption records, optionally grouped. Only when there is support for gas. + + There is quite some distinction between DSMR v4 and v5. DSMR v4 will update only once per hour and backtracks the + time by reporting it over the previous hour. + DSMR v5 will just allow small intervals, depending on whether the readings are grouped per minute or not. + """ + if not dsmr_reading.extra_device_timestamp or not dsmr_reading.extra_device_delivered: + # Some households aren't connected to a gas meter at all. + return + + read_at = dsmr_reading.extra_device_timestamp + dsmr_version = MeterStatistics.get_solo().dsmr_version + + # User requests grouping? We will truncate the 'seconds' marker, which will only affect DSMR v5 readings. + if grouping_type == ConsumptionSettings.COMPACTOR_GROUPING_BY_MINUTE: + read_at = read_at.replace(second=0, microsecond=0) + + # DSMR v4 readings should reflect to the previous hour, to keep it compatible with the existing implementation. + if dsmr_version is not None and dsmr_version.startswith('4'): + read_at = read_at - timezone.timedelta(hours=1) + + # We will not override data, just ignore it then. DSMR v4 will hit this a lot, DSMR v5 not. + if GasConsumption.objects.filter(read_at=read_at).exists(): + return + + # DSMR does not expose current gas rate, so we have to calculate it ourselves, relative to the previous gas + # consumption, if any. + try: + previous = GasConsumption.objects.all().order_by('-read_at')[0] + except IndexError: + gas_diff = 0 + else: + gas_diff = dsmr_reading.extra_device_delivered - previous.delivered + + GasConsumption.objects.create( + read_at=read_at, + delivered=dsmr_reading.extra_device_delivered, + currently_delivered=gas_diff + ) def consumption_by_range(start, end): diff --git a/dsmr_consumption/tests/test_services.py b/dsmr_consumption/tests/test_services.py index b329e8433..b7fe641c5 100644 --- a/dsmr_consumption/tests/test_services.py +++ b/dsmr_consumption/tests/test_services.py @@ -8,6 +8,7 @@ from dsmr_datalogger.models.reading import DsmrReading from dsmr_consumption.models.consumption import ElectricityConsumption, GasConsumption from dsmr_consumption.models.settings import ConsumptionSettings +from dsmr_datalogger.models.statistics import MeterStatistics import dsmr_consumption.services @@ -18,6 +19,8 @@ class TestServices(InterceptStdoutMixin, TestCase): def setUp(self): self.support_gas_readings = True self.assertEqual(DsmrReading.objects.all().count(), 3) + MeterStatistics.get_solo() + MeterStatistics.objects.all().update(dsmr_version='42') if self.support_gas_readings: self.assertTrue(DsmrReading.objects.unprocessed().exists()) @@ -48,6 +51,14 @@ def test_processing(self): if self.support_gas_readings: self.assertEqual(GasConsumption.objects.count(), 2) + self.assertEqual( + [x.read_at for x in GasConsumption.objects.all()], + [ + # Asume a one hour backtrack. + timezone.make_aware(timezone.datetime(2015, 11, 10, hour=18), timezone.utc), + timezone.make_aware(timezone.datetime(2015, 11, 10, hour=19), timezone.utc) + ] + ) else: self.assertEqual(GasConsumption.objects.count(), 0) @@ -260,6 +271,42 @@ def test_calculate_min_max_consumption_watt(self): self.assertEqual(min_max['max_watt'], 6123) +class TestServicesDSMRv5(InterceptStdoutMixin, TestCase): + """ Biggest difference is the interval of gas readings. """ + fixtures = ['dsmr_consumption/test_dsmrreading_v5.json'] + + def setUp(self): + self.assertEqual(DsmrReading.objects.all().count(), 6) + self.assertTrue(DsmrReading.objects.unprocessed().exists()) + ConsumptionSettings.get_solo() + MeterStatistics.get_solo() + MeterStatistics.objects.all().update(dsmr_version='50') + + def test_processing_grouped(self): + dsmr_consumption.services.compact_all() + + self.assertTrue(DsmrReading.objects.processed().exists()) + self.assertFalse(DsmrReading.objects.unprocessed().exists()) + self.assertEqual(GasConsumption.objects.count(), 4) + self.assertEqual( + [float(x.currently_delivered) for x in GasConsumption.objects.all()], + [0.0, 0.05, 0.03, 0.07] + ) + + def test_processing_ungrouped(self): + ConsumptionSettings.objects.update(compactor_grouping_type=ConsumptionSettings.COMPACTOR_GROUPING_BY_READING) + + dsmr_consumption.services.compact_all() + + self.assertTrue(DsmrReading.objects.processed().exists()) + self.assertFalse(DsmrReading.objects.unprocessed().exists()) + self.assertEqual(GasConsumption.objects.count(), 6) + self.assertEqual( + [float(x.currently_delivered) for x in GasConsumption.objects.all()], + [0.0, 0.05, 0.01, 0.01, 0.01, 0.07] + ) + + class TestServicesWithoutGas(TestServices): fixtures = ['dsmr_consumption/test_dsmrreading_without_gas.json'] diff --git a/dsmr_datalogger/admin.py b/dsmr_datalogger/admin.py index b054d47e2..c2bd95aed 100644 --- a/dsmr_datalogger/admin.py +++ b/dsmr_datalogger/admin.py @@ -4,7 +4,8 @@ from dsmr_backend.mixins import ReadOnlyAdminModel from .models.settings import DataloggerSettings -from .models.reading import DsmrReading, MeterStatistics +from .models.reading import DsmrReading +from dsmr_datalogger.models.statistics import MeterStatistics @admin.register(DataloggerSettings) diff --git a/dsmr_datalogger/dsmr.py b/dsmr_datalogger/dsmr.py index 2ed2ee69c..9642fded7 100644 --- a/dsmr_datalogger/dsmr.py +++ b/dsmr_datalogger/dsmr.py @@ -16,6 +16,7 @@ '0-1:24.2.1': ('extra_device_timestamp', 'extra_device_delivered'), # Static data, stored in database but only record of the last reading is preserved. + '1-3:0.2.8': 'dsmr_version', '0-0:96.14.0': 'electricity_tariff', '0-0:96.7.21': 'power_failure_count', '0-0:96.7.9': 'long_power_failure_count', diff --git a/dsmr_datalogger/management/commands/dsmr_datalogger.py b/dsmr_datalogger/management/commands/dsmr_datalogger.py index f86cd8635..87e30f082 100644 --- a/dsmr_datalogger/management/commands/dsmr_datalogger.py +++ b/dsmr_datalogger/management/commands/dsmr_datalogger.py @@ -10,13 +10,13 @@ class Command(InfiniteManagementCommandMixin, BaseCommand): help = _('Performs an DSMR P1 telegram reading on the COM port.') name = __name__ # Required for PID file. - sleep_time = 1 + sleep_time = 0.25 def run(self, **options): """ InfiniteManagementCommandMixin listens to handle() and calls run() in a loop. """ datalogger_settings = DataloggerSettings.get_solo() - # This should only by disabled when performing huge migrations. + # This should only be disabled when performing huge migrations. if not datalogger_settings.track: raise CommandError("Datalogger tracking is DISABLED!") diff --git a/dsmr_datalogger/management/commands/dsmr_fake_datasource.py b/dsmr_datalogger/management/commands/dsmr_fake_datasource.py index 8cf325727..cf9417bb3 100644 --- a/dsmr_datalogger/management/commands/dsmr_fake_datasource.py +++ b/dsmr_datalogger/management/commands/dsmr_fake_datasource.py @@ -1,21 +1,21 @@ from decimal import Decimal, ROUND_UP -from unittest import mock import random import time +import crcmod from django.core.management.base import BaseCommand, CommandError from django.utils.translation import ugettext as _ -from django.core.management import call_command from django.utils import timezone from django.conf import settings from dsmr_backend.mixins import InfiniteManagementCommandMixin +import dsmr_datalogger.services class Command(InfiniteManagementCommandMixin, BaseCommand): help = _('Generates a FAKE reading. DO NOT USE in production! Used for integration checks.') name = __name__ # Required for PID file. - sleep_time = 10 + sleep_time = 1 def add_arguments(self, parser): super(Command, self).add_arguments(parser) @@ -49,15 +49,10 @@ def run(self, **options): if not options.get('acked_warning'): raise CommandError(_('Intended usage is NOT production! Force by using --ack-to-mess-up-my-data')) - self._inject(options) + telegram = self._generate_data(options['with_gas'], options['with_electricity_returned']) + print(telegram) # For convenience - @mock.patch('dsmr_datalogger.services.read_telegram') - def _inject(self, options, read_telegram_mock): - """ Calls the regular DSMR datalogger, but injects it with random data using mock. """ - - # Prepare some random data, but which makes sense. - read_telegram_mock.return_value = self._generate_data(options['with_gas'], options['with_electricity_returned']) - call_command('dsmr_datalogger', run_once=True) + dsmr_datalogger.services.telegram_to_reading(data=telegram) def _generate_data(self, with_gas, with_electricity_returned): """ Generates 'random' data, but in a way that it keeps incrementing. """ @@ -75,10 +70,10 @@ def _generate_data(self, with_gas, with_electricity_returned): electricity_base = second_since * 0.00005 # Averages around 1500/1600 kWh for a year. electricity_1 = electricity_base - electricity_2 = electricity_1 * 0.8 # Consumption during daylight is a bit lower. + electricity_2 = electricity_1 * 0.6 # Consumption during daylight is a bit lower. electricity_1_returned = 0 electricity_2_returned = 0 - gas = electricity_base * 0.6 # Random as well. + gas = electricity_base * 0.3 # Random as well. currently_delivered = random.randint(0, 1500) * 0.001 # kW currently_returned = 0 @@ -89,54 +84,64 @@ def _generate_data(self, with_gas, with_electricity_returned): currently_returned = random.randint(0, 2500) * 0.001 # kW data = [ - "/XMX5LGBBFFB123456789\n", - "\n", - "1-3:0.2.8(40)\n", - "0-0:1.0.0({timestamp}W)\n".format( + "/XMX5LGBBFFB123456789\r\n", + "\r\n", + "1-3:0.2.8(40)\r\n", + "0-0:1.0.0({timestamp}W)\r\n".format( timestamp=now.strftime('%y%m%d%H%M%S') ), - "0-0:96.1.1(FAKE-FAKE-FAKE-FAKE-FAKE)\n", - "1-0:1.8.1({}*kWh)\n".format(self._round_precision(electricity_1, 10)), - "1-0:2.8.1({}*kWh)\n".format(self._round_precision(electricity_1_returned, 10)), - "1-0:1.8.2({}*kWh)\n".format(self._round_precision(electricity_2, 10)), - "1-0:2.8.2({}*kWh)\n".format(self._round_precision(electricity_2_returned, 10)), - "0-0:96.14.0(0001)\n", # Should switch high/low tariff, but not used anyway. - "1-0:1.7.0({}*kW)\n".format(self._round_precision(currently_delivered, 6)), - "1-0:2.7.0({}*kW)\n".format(self._round_precision(currently_returned, 6)), - "0-0:96.7.21(00003)\n", - "0-0:96.7.9(00000)\n", - "1-0:99.97.0(0)(0-0:96.7.19)\n", - "1-0:32.32.0(00001)\n", - "1-0:52.32.0(00002)\n", - "1-0:72.32.0(00003)\n", - "1-0:32.36.0(00000)\n", - "1-0:52.36.0(00000)\n", - "1-0:72.36.0(00000)\n", - "0-0:96.13.1()\n", - "0-0:96.13.0()\n", - "1-0:31.7.0(000*A)\n", - "1-0:51.7.0(000*A)\n", - "1-0:71.7.0(001*A)\n", - "1-0:21.7.0(00.000*kW)\n", - "1-0:41.7.0(00.000*kW)\n", - "1-0:61.7.0({}*kW)\n".format(self._round_precision(currently_delivered, 6)), - "1-0:22.7.0(00.000*kW)\n", - "1-0:42.7.0(00.000*kW)\n", - "1-0:62.7.0(00.000*kW)\n", - - "!D19A\n", + "0-0:96.1.1(FAKE-FAKE-FAKE-FAKE-FAKE)\r\n", + "1-0:1.8.1({}*kWh)\r\n".format(self._round_precision(electricity_1, 10)), + "1-0:2.8.1({}*kWh)\r\n".format(self._round_precision(electricity_1_returned, 10)), + "1-0:1.8.2({}*kWh)\r\n".format(self._round_precision(electricity_2, 10)), + "1-0:2.8.2({}*kWh)\r\n".format(self._round_precision(electricity_2_returned, 10)), + "0-0:96.14.0(0001)\r\n", # Should switch high/low tariff, but not used anyway. + "1-0:1.7.0({}*kW)\r\n".format(self._round_precision(currently_delivered, 6)), + "1-0:2.7.0({}*kW)\r\n".format(self._round_precision(currently_returned, 6)), + "0-0:96.7.21(00003)\r\n", + "0-0:96.7.9(00000)\r\n", + "1-0:99.97.0(0)(0-0:96.7.19)\r\n", + "1-0:32.32.0(00001)\r\n", + "1-0:52.32.0(00002)\r\n", + "1-0:72.32.0(00003)\r\n", + "1-0:32.36.0(00000)\r\n", + "1-0:52.36.0(00000)\r\n", + "1-0:72.36.0(00000)\r\n", + "0-0:96.13.1()\r\n", + "0-0:96.13.0()\r\n", + "1-0:31.7.0(000*A)\r\n", + "1-0:51.7.0(000*A)\r\n", + "1-0:71.7.0(001*A)\r\n", + "1-0:21.7.0(00.000*kW)\r\n", + "1-0:41.7.0(00.000*kW)\r\n", + "1-0:61.7.0({}*kW)\r\n".format(self._round_precision(currently_delivered, 6)), + "1-0:22.7.0(00.000*kW)\r\n", + "1-0:42.7.0(00.000*kW)\r\n", + "1-0:62.7.0(00.000*kW)\r\n", ] if with_gas: data += [ - "0-1:24.1.0(003)\n", - "0-1:96.1.0(FAKE-FAKE-FAKE-FAKE-FAKE)\n", - "0-1:24.2.1({}W)({}*m3)\n".format( + "0-1:24.1.0(003)\r\n", + "0-1:96.1.0(FAKE-FAKE-FAKE-FAKE-FAKE)\r\n", + "0-1:24.2.1({}W)({}*m3)\r\n".format( now.strftime('%y%m%d%H0000'), self._round_precision(gas, 9) ), ] - return ''.join(data) + data += ["!"] + telegram = "".join(data) + + # Sign the data with CRC as well. + crc16_function = crcmod.predefined.mkPredefinedCrcFun('crc16') + + unicode_telegram = telegram.encode('ascii') + calculated_checksum = crc16_function(unicode_telegram) + + hexed_checksum = hex(calculated_checksum)[2:].upper() + hexed_checksum = '{:0>4}'.format(hexed_checksum) # Zero any spacing on the left hand size. + + return "{}{}".format(telegram, hexed_checksum) def _round_precision(self, float_number, fill_count): """ Rounds the number for precision. """ diff --git a/dsmr_datalogger/migrations/0006_dsmr_firmware_v5.py b/dsmr_datalogger/migrations/0006_dsmr_firmware_v5.py new file mode 100644 index 000000000..08a3ee100 --- /dev/null +++ b/dsmr_datalogger/migrations/0006_dsmr_firmware_v5.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.4 on 2017-01-21 21:29 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dsmr_datalogger', '0005_verify_telegram_crc_setting'), + ] + + operations = [ + migrations.RemoveField( + model_name='dataloggersettings', + name='track_meter_statistics', + ), + migrations.AlterField( + model_name='dataloggersettings', + name='dsmr_version', + field=models.IntegerField(choices=[(4, 'DSMR version 4+'), (3, 'DSMR version 2')], default=4, help_text='The DSMR version your meter supports. Version should be printed on meter.', verbose_name='DSMR version'), + ), + migrations.AlterField( + model_name='meterstatistics', + name='timestamp', + field=models.DateTimeField(auto_now=True, help_text='Timestamp indicating when the reading was taken'), + ), + migrations.AddField( + model_name='meterstatistics', + name='dsmr_version', + field=models.CharField(default=None, help_text='DSMR version', max_length=2, null=True), + ), + ] diff --git a/dsmr_datalogger/models/reading.py b/dsmr_datalogger/models/reading.py index f7c85ec60..523894047 100644 --- a/dsmr_datalogger/models/reading.py +++ b/dsmr_datalogger/models/reading.py @@ -1,6 +1,6 @@ -from django.db import models from django.utils.translation import ugettext_lazy as _ -from solo.models import SingletonModel +from django.db import models +from django.utils import timezone class DsmrReadingManager(models.Manager): @@ -96,73 +96,6 @@ class Meta: verbose_name_plural = _('DSMR readings (read only)') def __str__(self): - return '{}: {} kWh'.format(self.id, self.timestamp, self.electricity_currently_delivered) - - -class MeterStatistics(SingletonModel): - """ Meter statistics, but only exists as a single record, containing the latest data. """ - timestamp = models.DateTimeField( - help_text=_("Timestamp indicating when the reading was taken, according to the meter"), - auto_now=True - ) - electricity_tariff = models.IntegerField( - help_text=_( - "Tariff indicator electricity. The tariff indicator can be used to switch tariff " - "dependent loads e.g boilers. This is responsibility of the P1 user. Note: Tariff " - "code 1 is used for low tariff and tariff code 2 is used for normal tariff." - ), - null=True, - default=None - ) - power_failure_count = models.IntegerField( - help_text=_("Number of power failures in any phases"), - null=True, - default=None - ) - long_power_failure_count = models.IntegerField( - help_text=_("Number of long power failures in any phase"), - null=True, - default=None - ) - voltage_sag_count_l1 = models.IntegerField( - help_text=_("Number of voltage sags/dips in phase L1"), - null=True, - default=None - ) - voltage_sag_count_l2 = models.IntegerField( - help_text=_("Number of voltage sags/dips in phase L2 (polyphase meters only)"), - null=True, - default=None - ) - voltage_sag_count_l3 = models.IntegerField( - help_text=_("Number of voltage sags/dips in phase L3 (polyphase meters only)"), - null=True, - default=None - ) - voltage_swell_count_l1 = models.IntegerField( - help_text=_("Number of voltage swells in phase L1"), - null=True, - default=None - ) - voltage_swell_count_l2 = models.IntegerField( - help_text=_("Number of voltage swells in phase L2 (polyphase meters only)"), - null=True, - default=None - ) - voltage_swell_count_l3 = models.IntegerField( - help_text=_("Number of voltage swells in phase L3 (polyphase meters only)"), - null=True, - default=None - ) - rejected_telegrams = models.IntegerField( - help_text=_("Number of rejected telegrams due to invalid CRC checksum"), - default=0 - ) - - class Meta: - default_permissions = tuple() - verbose_name = _('DSMR Meter statistics (read only)') - verbose_name_plural = verbose_name - - def __str__(self): - return '{} @ {}'.format(self.__class__.__name__, self.timestamp) + return '{} @ {} ({} kW)'.format( + self.id, timezone.localtime(self.timestamp), self.electricity_currently_delivered + ) diff --git a/dsmr_datalogger/models/settings.py b/dsmr_datalogger/models/settings.py index 7fd17dbb2..d5ec74a40 100644 --- a/dsmr_datalogger/models/settings.py +++ b/dsmr_datalogger/models/settings.py @@ -5,11 +5,11 @@ class DataloggerSettings(SingletonModel): """ Singleton model restricted by django-solo plugin. Settings for this application only. """ - DSMR_VERSION_4 = 4 - DSMR_VERSION_3 = 3 + DSMR_VERSION_4_PLUS = 4 + DSMR_VERSION_2 = 3 # Yes that is a three and it's legacy. DSMR_VERSION_CHOICES = ( - (DSMR_VERSION_4, _('DSMR version 4')), - (DSMR_VERSION_3, _('DSMR version 2/3')), + (DSMR_VERSION_4_PLUS, _('DSMR version 4+')), + (DSMR_VERSION_2, _('DSMR version 2')), ) track = models.BooleanField( @@ -21,14 +21,6 @@ class DataloggerSettings(SingletonModel): 'due to technical reasons, such as data migrations.' ) ) - track_meter_statistics = models.BooleanField( - default=True, - verbose_name=_('Track meter statistics'), - help_text=_( - 'Whether we should track any extra statistics sent by the meter, such as the number of ' - 'power failures of voltage dips. Data is not required for core features.' - ) - ) track_phases = models.BooleanField( default=False, verbose_name=_('Track electricity phases'), @@ -45,7 +37,7 @@ class DataloggerSettings(SingletonModel): ) dsmr_version = models.IntegerField( - default=DSMR_VERSION_4, + default=DSMR_VERSION_4_PLUS, choices=DSMR_VERSION_CHOICES, verbose_name=_('DSMR version'), help_text=_('The DSMR version your meter supports. Version should be printed on meter.') diff --git a/dsmr_datalogger/models/statistics.py b/dsmr_datalogger/models/statistics.py new file mode 100644 index 000000000..dd9fddf25 --- /dev/null +++ b/dsmr_datalogger/models/statistics.py @@ -0,0 +1,78 @@ +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from solo.models import SingletonModel + + +class MeterStatistics(SingletonModel): + """ Meter statistics, but only exists as a single record, containing the latest data. """ + timestamp = models.DateTimeField( + help_text=_("Timestamp indicating when the reading was taken"), + auto_now=True + ) + dsmr_version = models.CharField( + help_text=_("DSMR version"), + max_length=2, + null=True, + default=None + ) + electricity_tariff = models.IntegerField( + help_text=_( + "Tariff indicator electricity. The tariff indicator can be used to switch tariff " + "dependent loads e.g boilers. This is responsibility of the P1 user. Note: Tariff " + "code 1 is used for low tariff and tariff code 2 is used for normal tariff." + ), + null=True, + default=None + ) + power_failure_count = models.IntegerField( + help_text=_("Number of power failures in any phases"), + null=True, + default=None + ) + long_power_failure_count = models.IntegerField( + help_text=_("Number of long power failures in any phase"), + null=True, + default=None + ) + voltage_sag_count_l1 = models.IntegerField( + help_text=_("Number of voltage sags/dips in phase L1"), + null=True, + default=None + ) + voltage_sag_count_l2 = models.IntegerField( + help_text=_("Number of voltage sags/dips in phase L2 (polyphase meters only)"), + null=True, + default=None + ) + voltage_sag_count_l3 = models.IntegerField( + help_text=_("Number of voltage sags/dips in phase L3 (polyphase meters only)"), + null=True, + default=None + ) + voltage_swell_count_l1 = models.IntegerField( + help_text=_("Number of voltage swells in phase L1"), + null=True, + default=None + ) + voltage_swell_count_l2 = models.IntegerField( + help_text=_("Number of voltage swells in phase L2 (polyphase meters only)"), + null=True, + default=None + ) + voltage_swell_count_l3 = models.IntegerField( + help_text=_("Number of voltage swells in phase L3 (polyphase meters only)"), + null=True, + default=None + ) + rejected_telegrams = models.IntegerField( + help_text=_("Number of rejected telegrams due to invalid CRC checksum"), + default=0 + ) + + class Meta: + default_permissions = tuple() + verbose_name = _('DSMR Meter statistics (read only)') + verbose_name_plural = verbose_name + + def __str__(self): + return '{} @ {}'.format(self.__class__.__name__, self.timestamp) diff --git a/dsmr_datalogger/services.py b/dsmr_datalogger/services.py index 0c5c9c850..59613b103 100644 --- a/dsmr_datalogger/services.py +++ b/dsmr_datalogger/services.py @@ -10,7 +10,8 @@ import crcmod import pytz -from dsmr_datalogger.models.reading import DsmrReading, MeterStatistics +from dsmr_datalogger.models.reading import DsmrReading +from dsmr_datalogger.models.statistics import MeterStatistics from dsmr_datalogger.models.settings import DataloggerSettings from dsmr_datalogger.exceptions import InvalidTelegramChecksum from dsmr_datalogger.dsmr import DSMR_MAPPING @@ -22,13 +23,13 @@ def get_dsmr_connection_parameters(): """ Returns the communication settings required for the DSMR version set. """ DSMR_VERSION_MAPPING = { - DataloggerSettings.DSMR_VERSION_3: { + DataloggerSettings.DSMR_VERSION_2: { 'baudrate': 9600, 'bytesize': serial.SEVENBITS, 'parity': serial.PARITY_EVEN, 'crc': False, }, - DataloggerSettings.DSMR_VERSION_4: { + DataloggerSettings.DSMR_VERSION_4_PLUS: { 'baudrate': 115200, 'bytesize': serial.EIGHTBITS, 'parity': serial.PARITY_NONE, @@ -104,7 +105,7 @@ def verify_telegram_checksum(data): Verifies telegram by checking it's CRC. Raises exception on failure. DSMR docs state: CRC is a CRC16 value calculated over the preceding characters in the data message (from / to ! using the polynomial) """ - matches = re.search(r'^(/[^!]+!)([A-Z0-9]{4,4})', data) + matches = re.search(r'^(/[^!]+!)([A-Z0-9]{4})', data) try: content, crc = matches.groups() @@ -129,46 +130,39 @@ def verify_telegram_checksum(data): ) -def telegram_to_reading(data): # noqa: C901 - """ - Converts a P1 telegram to a DSMR reading, which will be stored in database. - """ +def _convert_legacy_dsmr_gas_line(parsed_reading, current_line, next_line): + """ Legacy support for DSMR 2.x gas. """ + legacy_gas_line = current_line - def _get_reading_fields(): - reading_fields = [x.name for x in DsmrReading._meta.get_fields()] - reading_fields.remove('id') - reading_fields.remove('processed') - return reading_fields + if next_line.startswith('('): # pragma: no cover + legacy_gas_line = current_line + next_line - def _get_statistics_fields(): - reading_fields = [x.name for x in MeterStatistics._meta.get_fields()] - reading_fields.remove('id') - reading_fields.remove('rejected_telegrams') - return reading_fields + legacy_gas_result = re.search( + r'[^(]+\((\d+)\)\(\d+\)\(\d+\)\(\d+\)\([0-9-.:]+\)\(m3\)\(([0-9.]+)\)', + legacy_gas_line + ) + gas_timestamp = legacy_gas_result.group(1) - def _convert_legacy_dsmr_gas_line(parsed_reading, current_line, next_line): - """ Legacy support for DSMR 2.x gas. """ - legacy_gas_line = current_line + if timezone.now().dst() != timezone.timedelta(0): + gas_timestamp += 'S' + else: + gas_timestamp += 'W' - if next_line.startswith('('): # pragma: no cover - legacy_gas_line = current_line + next_line + parsed_reading['extra_device_timestamp'] = reading_timestamp_to_datetime( + string=gas_timestamp + ) + parsed_reading['extra_device_delivered'] = legacy_gas_result.group(2) + return parsed_reading - legacy_gas_result = re.search( - r'[^(]+\((\d+)\)\(\d+\)\(\d+\)\(\d+\)\([0-9-.:]+\)\(m3\)\(([0-9.]+)\)', - legacy_gas_line - ) - gas_timestamp = legacy_gas_result.group(1) - if timezone.now().dst() != timezone.timedelta(0): - gas_timestamp += 'S' - else: - gas_timestamp += 'W' - - parsed_reading['extra_device_timestamp'] = reading_timestamp_to_datetime( - string=gas_timestamp - ) - parsed_reading['extra_device_delivered'] = legacy_gas_result.group(2) - return parsed_reading +def telegram_to_reading(data): # noqa: C901 + """ + Converts a P1 telegram to a DSMR reading, which will be stored in database. + """ + READING_FIELDS = [x.name for x in DsmrReading._meta.get_fields() if x.name not in ('id', 'processed')] + STATISTICS_FIELDS = [ + x.name for x in MeterStatistics._meta.get_fields() if x.name not in ('id', 'rejected_telegrams') + ] # We will log the telegrams in base64 for convenience and debugging 'n stuff. base64_data = base64.b64encode(data.encode()) @@ -189,7 +183,7 @@ def _convert_legacy_dsmr_gas_line(parsed_reading, current_line, next_line): raise # Defaults all fields to NULL. - parsed_reading = {k: None for k in _get_reading_fields() + _get_statistics_fields()} + parsed_reading = {k: None for k in READING_FIELDS + STATISTICS_FIELDS} field_splitter = re.compile(r'([^(]+)\((.+)\)') lines_read = data.split("\r\n") @@ -246,14 +240,14 @@ def _convert_legacy_dsmr_gas_line(parsed_reading, current_line, next_line): }) # Now we need to split reading & statistics. So we split the dict here. - reading_kwargs = {k: parsed_reading[k] for k in _get_reading_fields()} + reading_kwargs = {k: parsed_reading[k] for k in READING_FIELDS} + statistics_kwargs = {k: parsed_reading[k] for k in STATISTICS_FIELDS} + + # Reading will be processed later. new_reading = DsmrReading.objects.create(**reading_kwargs) - # Optional feature. - if datalogger_settings.track_meter_statistics: - statistics_kwargs = {k: parsed_reading[k] for k in _get_statistics_fields()} - # There should already be one in database, created when migrating. - MeterStatistics.objects.all().update(**statistics_kwargs) + # There should already be one in database, created when migrating. + MeterStatistics.objects.all().update(**statistics_kwargs) logger.info('Received telegram (base64 encoded): {}'.format(base64_data)) return new_reading diff --git a/dsmr_datalogger/tests/datalogger/test_generic.py b/dsmr_datalogger/tests/datalogger/test_generic.py index 9c71946c8..8c4be01b2 100644 --- a/dsmr_datalogger/tests/datalogger/test_generic.py +++ b/dsmr_datalogger/tests/datalogger/test_generic.py @@ -9,7 +9,8 @@ from dsmr_backend.tests.mixins import InterceptStdoutMixin from dsmr_datalogger.models.settings import DataloggerSettings -from dsmr_datalogger.models.reading import DsmrReading, MeterStatistics +from dsmr_datalogger.models.reading import DsmrReading +from dsmr_datalogger.models.statistics import MeterStatistics from dsmr_datalogger.exceptions import InvalidTelegramChecksum import dsmr_datalogger.services @@ -111,10 +112,6 @@ def test_reading_timestamp_to_datetime(self): self.assertEqual(result, expected_result) def test_track_meter_statistics(self): - datalogger_settings = DataloggerSettings.get_solo() - datalogger_settings.track_meter_statistics = False - datalogger_settings.save() - telegram = ''.join([ "/XMX5LGBBFFB123456789\r\n", "\r\n", @@ -157,20 +154,12 @@ def test_track_meter_statistics(self): "!AF0C\n", ]) - self.assertIsNone(MeterStatistics.get_solo().electricity_tariff) # Empty model in DB. - dsmr_datalogger.services.telegram_to_reading(data=telegram) - self.assertIsNone(MeterStatistics.get_solo().electricity_tariff) # Unaffected - - # Try again, but now with tracking settings enabled. - datalogger_settings = DataloggerSettings.get_solo() - datalogger_settings.track_meter_statistics = True - datalogger_settings.save() - self.assertIsNone(MeterStatistics.get_solo().electricity_tariff) # Empty model in DB. dsmr_datalogger.services.telegram_to_reading(data=telegram) # Should be populated now. meter_statistics = MeterStatistics.get_solo() + self.assertEqual(meter_statistics.dsmr_version, '40') self.assertIsNotNone(meter_statistics.electricity_tariff) self.assertEqual(meter_statistics.electricity_tariff, 1) self.assertEqual(meter_statistics.power_failure_count, 3) @@ -292,6 +281,11 @@ def test_verify_telegram_checksum(self): ] with self.assertRaises(InvalidTelegramChecksum): + # Empty. + dsmr_datalogger.services.verify_telegram_checksum(data='') + + with self.assertRaises(InvalidTelegramChecksum): + # Invalid checksum. dsmr_datalogger.services.verify_telegram_checksum(data=''.join(telegram)) # Again, with the correct checksum. @@ -300,22 +294,22 @@ def test_verify_telegram_checksum(self): class TestDsmrVersionMapping(InterceptStdoutMixin, TestCase): - def test_dsmr_version_3(self): - """ Test connection parameters for DSMR v2/3. """ + def test_dsmr_version_2(self): + """ Test connection parameters for DSMR v2. """ datalogger_settings = DataloggerSettings.get_solo() - datalogger_settings.dsmr_version = DataloggerSettings.DSMR_VERSION_3 + datalogger_settings.dsmr_version = DataloggerSettings.DSMR_VERSION_2 datalogger_settings.save() - self.assertEqual(DataloggerSettings.get_solo().dsmr_version, DataloggerSettings.DSMR_VERSION_3) + self.assertEqual(DataloggerSettings.get_solo().dsmr_version, DataloggerSettings.DSMR_VERSION_2) connection_parameters = dsmr_datalogger.services.get_dsmr_connection_parameters() self.assertEqual(connection_parameters['baudrate'], 9600) self.assertEqual(connection_parameters['bytesize'], serial.SEVENBITS) self.assertEqual(connection_parameters['parity'], serial.PARITY_EVEN) - def test_dsmr_version_4(self): - """ Test connection parameters for DSMR v4. """ - self.assertEqual(DataloggerSettings.get_solo().dsmr_version, DataloggerSettings.DSMR_VERSION_4) + def test_dsmr_version_4_plus(self): + """ Test connection parameters for DSMR v4+. """ + self.assertEqual(DataloggerSettings.get_solo().dsmr_version, DataloggerSettings.DSMR_VERSION_4_PLUS) connection_parameters = dsmr_datalogger.services.get_dsmr_connection_parameters() self.assertEqual(connection_parameters['baudrate'], 115200) diff --git a/dsmr_datalogger/tests/datalogger/test_iskra.py b/dsmr_datalogger/tests/datalogger/test_iskra.py index 6470a16c6..87c91a44a 100644 --- a/dsmr_datalogger/tests/datalogger/test_iskra.py +++ b/dsmr_datalogger/tests/datalogger/test_iskra.py @@ -7,7 +7,8 @@ import pytz from dsmr_backend.tests.mixins import InterceptStdoutMixin -from dsmr_datalogger.models.reading import DsmrReading, MeterStatistics +from dsmr_datalogger.models.reading import DsmrReading +from dsmr_datalogger.models.statistics import MeterStatistics from dsmr_datalogger.models.settings import DataloggerSettings @@ -15,7 +16,7 @@ class TestDatalogger(InterceptStdoutMixin, TestCase): """ Test Iskra meter, unknown DSMR version. """ def setUp(self): datalogger_settings = DataloggerSettings.get_solo() - datalogger_settings.dsmr_version = DataloggerSettings.DSMR_VERSION_3 + datalogger_settings.dsmr_version = DataloggerSettings.DSMR_VERSION_2 datalogger_settings.save() def _dsmr_dummy_data(self): diff --git a/dsmr_datalogger/tests/datalogger/test_kaifa_dsmr42.py b/dsmr_datalogger/tests/datalogger/test_kaifa_dsmr42.py index 29cb0a5df..31abae117 100644 --- a/dsmr_datalogger/tests/datalogger/test_kaifa_dsmr42.py +++ b/dsmr_datalogger/tests/datalogger/test_kaifa_dsmr42.py @@ -6,7 +6,8 @@ import pytz from dsmr_backend.tests.mixins import InterceptStdoutMixin -from dsmr_datalogger.models.reading import DsmrReading, MeterStatistics +from dsmr_datalogger.models.reading import DsmrReading +from dsmr_datalogger.models.statistics import MeterStatistics from dsmr_datalogger.models.settings import DataloggerSettings @@ -82,6 +83,7 @@ def test_reading_values(self): self.assertEqual(reading.phase_currently_delivered_l3, None) meter_statistics = MeterStatistics.get_solo() + self.assertEqual(meter_statistics.dsmr_version, '42') self.assertEqual(meter_statistics.electricity_tariff, 2) self.assertEqual(meter_statistics.power_failure_count, 6) self.assertEqual(meter_statistics.long_power_failure_count, 3) diff --git a/dsmr_datalogger/tests/datalogger/test_landisgyr350_dsmr40.py b/dsmr_datalogger/tests/datalogger/test_landisgyr350_dsmr40.py index 8a2f26aa1..31b5914f8 100644 --- a/dsmr_datalogger/tests/datalogger/test_landisgyr350_dsmr40.py +++ b/dsmr_datalogger/tests/datalogger/test_landisgyr350_dsmr40.py @@ -6,7 +6,8 @@ import pytz from dsmr_backend.tests.mixins import InterceptStdoutMixin -from dsmr_datalogger.models.reading import DsmrReading, MeterStatistics +from dsmr_datalogger.models.reading import DsmrReading +from dsmr_datalogger.models.statistics import MeterStatistics from dsmr_datalogger.models.settings import DataloggerSettings @@ -100,6 +101,7 @@ def test_reading_values(self): # Different data source. meter_statistics = MeterStatistics.get_solo() + self.assertEqual(meter_statistics.dsmr_version, '40') self.assertEqual(meter_statistics.electricity_tariff, Decimal('1')) self.assertEqual(meter_statistics.power_failure_count, 3) self.assertEqual(meter_statistics.long_power_failure_count, 0) diff --git a/dsmr_datalogger/tests/datalogger/test_landisgyr350_dsmr42.py b/dsmr_datalogger/tests/datalogger/test_landisgyr350_dsmr42.py index 40517c7bd..622b6e6f7 100644 --- a/dsmr_datalogger/tests/datalogger/test_landisgyr350_dsmr42.py +++ b/dsmr_datalogger/tests/datalogger/test_landisgyr350_dsmr42.py @@ -6,7 +6,8 @@ import pytz from dsmr_backend.tests.mixins import InterceptStdoutMixin -from dsmr_datalogger.models.reading import DsmrReading, MeterStatistics +from dsmr_datalogger.models.reading import DsmrReading +from dsmr_datalogger.models.statistics import MeterStatistics from dsmr_datalogger.models.settings import DataloggerSettings @@ -99,6 +100,7 @@ def test_reading_values(self): # Different data source. meter_statistics = MeterStatistics.get_solo() + self.assertEqual(meter_statistics.dsmr_version, '42') self.assertEqual(meter_statistics.electricity_tariff, 2) self.assertEqual(meter_statistics.power_failure_count, 3) self.assertEqual(meter_statistics.long_power_failure_count, 0) diff --git a/dsmr_datalogger/tests/datalogger/test_landisgyr350_other_dsmr42.py b/dsmr_datalogger/tests/datalogger/test_landisgyr350_other_dsmr42.py index 6866a90cb..92fc742d1 100644 --- a/dsmr_datalogger/tests/datalogger/test_landisgyr350_other_dsmr42.py +++ b/dsmr_datalogger/tests/datalogger/test_landisgyr350_other_dsmr42.py @@ -6,7 +6,8 @@ import pytz from dsmr_backend.tests.mixins import InterceptStdoutMixin -from dsmr_datalogger.models.reading import DsmrReading, MeterStatistics +from dsmr_datalogger.models.reading import DsmrReading +from dsmr_datalogger.models.statistics import MeterStatistics from dsmr_datalogger.models.settings import DataloggerSettings @@ -89,6 +90,7 @@ def test_reading_values(self): # Different data source. meter_statistics = MeterStatistics.get_solo() + self.assertEqual(meter_statistics.dsmr_version, '42') self.assertEqual(meter_statistics.electricity_tariff, 2) self.assertEqual(meter_statistics.power_failure_count, 8) self.assertEqual(meter_statistics.long_power_failure_count, 0) diff --git a/dsmr_datalogger/tests/models/test_reading.py b/dsmr_datalogger/tests/models/test_reading.py index e190adfd2..55d41b3ec 100644 --- a/dsmr_datalogger/tests/models/test_reading.py +++ b/dsmr_datalogger/tests/models/test_reading.py @@ -1,7 +1,8 @@ from django.test import TestCase from django.utils import timezone -from dsmr_datalogger.models.reading import DsmrReading, MeterStatistics +from dsmr_datalogger.models.reading import DsmrReading +from dsmr_datalogger.models.statistics import MeterStatistics class TestDsmrReading(TestCase): @@ -24,6 +25,11 @@ def test_str(self): """ Model should override string formatting. """ self.assertNotEqual(str(self.instance), 'DsmrReading') + def test_managers(self): + self.assertTrue(DsmrReading.objects.unprocessed().exists()) + DsmrReading.objects.all().update(processed=True) + self.assertTrue(DsmrReading.objects.processed().exists()) + class TestMeterStatistics(TestCase): def setUp(self): diff --git a/dsmr_datalogger/tests/models/test_settings.py b/dsmr_datalogger/tests/models/test_settings.py index 14672da25..2beab3c93 100644 --- a/dsmr_datalogger/tests/models/test_settings.py +++ b/dsmr_datalogger/tests/models/test_settings.py @@ -19,9 +19,6 @@ def test_to_string(self): def test_track(self): self.assertTrue(self.instance.track) - def test_track_meter_statistics(self): - self.assertTrue(self.instance.track_meter_statistics) - def test_track_phases(self): self.assertFalse(self.instance.track_phases) @@ -29,7 +26,7 @@ def test_verify_telegram_crc(self): self.assertTrue(self.instance.verify_telegram_crc) def test_dsmr_version(self): - self.assertEqual(self.instance.dsmr_version, DataloggerSettings.DSMR_VERSION_4) + self.assertEqual(self.instance.dsmr_version, DataloggerSettings.DSMR_VERSION_4_PLUS) def test_com_port(self): self.assertEqual(self.instance.com_port, '/dev/ttyUSB0') diff --git a/dsmr_frontend/forms.py b/dsmr_frontend/forms.py index fd43ad147..0bd2aff4c 100644 --- a/dsmr_frontend/forms.py +++ b/dsmr_frontend/forms.py @@ -21,15 +21,22 @@ class ExportAsCsvForm(forms.Form): class DashboardGraphForm(forms.Form): - units_offset = forms.IntegerField(required=False) + electricity_offset = forms.IntegerField(required=False) + gas_offset = forms.IntegerField(required=False) - def clean_units_offset(self): - units_offset = self.cleaned_data['units_offset'] + def _clean_offset(self, offset_type): + offset = self.cleaned_data[offset_type] - if units_offset is None or units_offset < 0: - units_offset = 0 + if offset is None or offset < 0: + offset = 0 - return units_offset + return offset + + def clean_electricity_offset(self): + return self._clean_offset('electricity_offset') + + def clean_gas_offset(self): + return self._clean_offset('gas_offset') class DashboardNotificationReadForm(forms.Form): diff --git a/dsmr_frontend/static/dsmr_frontend/css/dsmrreader.css b/dsmr_frontend/static/dsmr_frontend/css/dsmrreader.css index c8f167704..5a080e0d8 100644 --- a/dsmr_frontend/static/dsmr_frontend/css/dsmrreader.css +++ b/dsmr_frontend/static/dsmr_frontend/css/dsmrreader.css @@ -8,7 +8,7 @@ div.copyright { width: 100%; text-align: center; color: white; - height: 64px; + height: 96px; padding-left: 24px; } diff --git a/dsmr_frontend/static/dsmr_frontend/img/GitHub-Mark-32px.png b/dsmr_frontend/static/dsmr_frontend/img/GitHub-Mark-32px.png new file mode 100644 index 0000000000000000000000000000000000000000..8b25551a97921681334176ee143b41510a117d86 GIT binary patch literal 1714 zcmaJ?X;2eq7*4oFu!ne{XxAht2qc?8LXr|_LPCfTpaBK7K$c{I0Ld=NLIOeuC;@2) zZ$K%a)k+m-s0>xHmKxL%0V&0TRzzznhgyqrIC$F)0{WwLXLrBvd*^wc_uSc%h%m9E z{W5z3f#4_!7RvAyFh6!S_*<8qJ%KOIm?#E|L=rJQq=gB5C6WLG5;c?r%V0>EmEH#X z5eSwPRa6WXBMs#$5H%GtW2go-in9p>zW@UYDNNWc^XOXZQ? z1QjEV00I#$3^1wQUJ8&-2UsjB-G|9y(LDhMNN3PM{APL4eYi{(m*ERcUnJa{R+-3^ z34^A6;U^v`8N*O6ji%S@sd{fJqD`XFIUJ5zgTe5^5nj414F(y!G&=H(f)Lgzv?>%+ zAsWD}2qhpH7>|TU`X&W6IxDNuO_vET7|j5oG&&VDr!)hUO8+0KR?nh!m<)a!?|%yG zqOwq!CWCcIhE{<$E|F|@g>nP6FoYr6C<8>D?ID9%&5J(4oSbR1I^byW*g@__U z4QsF&uJSEcFeleM3~ChjEQGbHOjsGDMbyAl(p=Ttv9RaVo8~I#js@@Y9C^_2U})yn zzSHU%6FxuY?d;&65MyR({^lU*3$z$ZllDb(o&<7d;A_`h2U+3~BJ2Hv`{W}KEU801#cv_B|9Cm!ynR{S`AMsSn z;7E=B;mb!wx$L;S>yGXG^6=&WlQn9$s?&L%Y1D8TI^MlKB1DqsEng$>f4=xYWBoPI z_S1p!sJ#d2?YI4kPA{k}Eby?F=f-J9zIc`YDl^pzjVm~9ebE?Hn?t0Nx+la|D0MB; z9)2xv1G>a1|A9kQ>~DV<=X3-4yC&n!m8-3K#P z{X@0zRuQsy$+N ziSCoLJU{Z$nQy4A4Y5UJ07$5FA~qL2%Q+cLaqDU?Lz3?=BC5;Nk6BbTmmceEaM>-Z zi>O&-dSE=%ex;vcvCOk{*JQ5^_4M z4lW7%l9IqY(z7pV(?I@@8=KPFO82)O{VDI18-*d-k$YmI^XiuPs_LuFw<^ZcD}yP5 c*NrbeloN*74g`U%%F6r~k%+>C^#XapzmV0H-2eap literal 0 HcmV?d00001 diff --git a/dsmr_frontend/static/dsmr_frontend/img/favicon.png b/dsmr_frontend/static/dsmr_frontend/img/favicon.png deleted file mode 100644 index 261af2050d5e35b19e4c1e26f6bfb0145430bda8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2071 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 literal 0 HcmV?d00001 diff --git a/dsmr_frontend/static/dsmr_frontend/img/favicons/apple-touch-icon.png b/dsmr_frontend/static/dsmr_frontend/img/favicons/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..dc7a787f9aae530fa397e41223c8dde40892548e GIT binary patch literal 5155 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 LtJ + + + + + #da532c + + + diff --git a/dsmr_frontend/static/dsmr_frontend/img/favicons/favicon-16x16.png b/dsmr_frontend/static/dsmr_frontend/img/favicons/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..436a0f67e7d05460654bef413f89337bd48644fc GIT binary patch literal 1086 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>`1HQ44@YIii(4o7*$XeYh7ML)4s5haGZYa4FB}=n`<%ap7Fl7LnN8 z)!LA^DCxcEo6>*(neV)?ytBPJKCOkrF}m7a-GzHW_r!M^QMWGNc0cy(@qzv7J&ajw zlRGysIJ;%dP+lzKJ^S&l1f}Fu^_jCDed(Ed^7Vr=NquwTA3PG`;&TbSRdDi>QFvJ5 z=|vk-B(tCVVl!{tw8iD<*MPN!t3__J*<2Sp#XsTR&AZ)K7CSu9Zv4x<;_%|flexY$ z2k$K^dlzr<>66#*uV>ftm4D}Nb=$Nu*4D1|_`LYI+4E+$dr4kBcK_>khKm0`{uu4A z-}0Ynrmx!KW9pp1uwYOvag8WRNi0dVN-jzTQVd20hUU5kM!JTkA%^BwCWcl9M%o5I z(tvIKkFO{ia`RI%(<*UmDF5W(3Dh77vLQG>t)x7$D3zhSyj(9cFS|H7u^?41zbJk7 zI~ysWqVTGah?1bha)pAT{ItxRRE3htf>edff|6tghKf0lKk;xBhG}S=@;`mX^Jx$R zvog0{GPkg@u=ivUW?==F29v`n%*vZX6i(l`a^lFDBQi(WPd9ih@X}*=B`#R<$;oso P&!lvVtU&J%W50 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 literal 0 HcmV?d00001 diff --git a/dsmr_frontend/static/dsmr_frontend/img/favicons/manifest.json b/dsmr_frontend/static/dsmr_frontend/img/favicons/manifest.json new file mode 100644 index 000000000..4fbe18185 --- /dev/null +++ b/dsmr_frontend/static/dsmr_frontend/img/favicons/manifest.json @@ -0,0 +1,18 @@ +{ + "name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/dsmr_frontend/static/dsmr_frontend/img/favicons/mstile-150x150.png b/dsmr_frontend/static/dsmr_frontend/img/favicons/mstile-150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..e28849d8206b79ff66bf7324acfe643948246894 GIT binary patch literal 6814 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 + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + diff --git a/dsmr_frontend/templates/dsmr_frontend/base.html b/dsmr_frontend/templates/dsmr_frontend/base.html index 8876b95bd..8e8a8f051 100644 --- a/dsmr_frontend/templates/dsmr_frontend/base.html +++ b/dsmr_frontend/templates/dsmr_frontend/base.html @@ -1,6 +1,8 @@ {% load staticfiles %} {% load i18n %} +{% get_current_language as LANGUAGE_CODE %} + @@ -13,10 +15,16 @@ - + {% endblock %} - - + + + + + + + + @@ -134,10 +142,14 @@ diff --git a/dsmr_frontend/templates/dsmr_frontend/dashboard.html b/dsmr_frontend/templates/dsmr_frontend/dashboard.html index 5ce2b45a2..0ba20c254 100644 --- a/dsmr_frontend/templates/dsmr_frontend/dashboard.html +++ b/dsmr_frontend/templates/dsmr_frontend/dashboard.html @@ -6,7 +6,17 @@ {% block title %}{% trans "Dashboard" %}{% endblock %} {% block header %}{% trans "Dashboard" %}   {% endblock %} - + + +{% block stylesheets %} + {{ block.super }} + + +{% endblock %} + {% block header_right %}
  • @@ -243,13 +253,13 @@

    - - - + + +   - - - + + +

    {% endif %} @@ -282,6 +292,22 @@ + +
    +
    {% trans 'Scroll gas graph(s)' %}
    + ({% trans 'You can scroll back until one week ago' %}) +

    +
    +
    + + + +   + + + +
    +
    {% endif %} {% if capabilities.weather %} @@ -322,7 +348,8 @@ phases: undefined, temperature: undefined, } - var g_chart_offset = 0; + var g_chart_electricity_offset = 0; + var g_chart_gas_offset = 0; $(document).ready(function(){ $(".delete-notification").click(function(){ @@ -342,16 +369,29 @@ $(this).parent().hide(); $("#phases_holder").show(); return false - }); + }); - $(".x-offset-control").click(function(){ - g_chart_offset += parseInt($(this).attr('data-offset')); + $(".x-electricity-offset-control").click(function(){ + g_chart_electricity_offset += parseInt($(this).attr('data-offset')); /* Restrict range, server doesn't allow it either anyway. */ - if (g_chart_offset < 0) - { - g_chart_offset = 0; - } + if (g_chart_electricity_offset < 0) + { + g_chart_electricity_offset = 0; + } + + update_graphs(); + return false + }); + + $(".x-gas-offset-control").click(function(){ + g_chart_gas_offset += parseInt($(this).attr('data-offset')); + + /* Restrict range, server doesn't allow it either anyway. */ + if (g_chart_gas_offset < 0) + { + g_chart_gas_offset = 0; + } update_graphs(); return false @@ -395,7 +435,7 @@ { $.ajax({ dataType: "json", - url: "{% url 'frontend:dashboard-xhr-graphs' %}?units_offset=" + g_chart_offset, + url: "{% url 'frontend:dashboard-xhr-graphs' %}?electricity_offset=" + g_chart_electricity_offset, }).done(function(response) { if (response.capabilities.electricity) { @@ -513,7 +553,7 @@ { $.ajax({ dataType: "json", - url: "{% url 'frontend:dashboard-xhr-graphs' %}?units_offset=" + g_chart_offset, + url: "{% url 'frontend:dashboard-xhr-graphs' %}?electricity_offset=" + g_chart_electricity_offset + "&gas_offset=" + g_chart_gas_offset, }).done(function(response) { if (response.capabilities.electricity) { @@ -531,6 +571,11 @@ update_chart("phases", response.electricity_x, [response.phases_l1_y, response.phases_l2_y, response.phases_l3_y]); } {% endif %} + + if (response.capabilities.gas) + { + update_chart("gas", response.gas_x, [response.gas_y]); + } }); } diff --git a/dsmr_frontend/templates/dsmr_frontend/statistics.html b/dsmr_frontend/templates/dsmr_frontend/statistics.html index 04457f9a9..63f08c8a7 100644 --- a/dsmr_frontend/templates/dsmr_frontend/statistics.html +++ b/dsmr_frontend/templates/dsmr_frontend/statistics.html @@ -92,7 +92,6 @@ {% trans "Meter statistics" %}
    - {% if datalogger_settings.track_meter_statistics %} {% if meter_statistics.power_failure_count %} @@ -143,11 +142,6 @@ {% endif %}
    - {% else %} - - {% endif %}
    diff --git a/dsmr_frontend/templates/dsmr_frontend/status.html b/dsmr_frontend/templates/dsmr_frontend/status.html index 418c423dc..86e1e5c5a 100644 --- a/dsmr_frontend/templates/dsmr_frontend/status.html +++ b/dsmr_frontend/templates/dsmr_frontend/status.html @@ -32,8 +32,8 @@ {% trans "Check for updates" %}
    - {% trans "How does it work?" %} - {% blocktrans %}The application will compare "VERSION = (x,x,x)" in your local dsmrreader/__init__.py file with the latest one available on Github.{% endblocktrans %} + {% trans "How does it work?" %} + {% blocktrans %}The application will compare "VERSION = (x,x,x)" in your local dsmrreader/__init__.py file with the latest one available on Github.{% endblocktrans %}   {% trans 'Check now' %} @@ -58,7 +58,7 @@   {% trans "P1 DSMR telegrams" %}
    - {% if delta_since_latest_reading == None or delta_since_latest_reading > 60 %} + {% if delta_since_latest_reading == None or delta_since_latest_reading > 90 %} + +
    + {% trans "Click for more information" %} + + {% blocktrans %}The telegrams are either read from the DSMR_DATALOGGER process or sent via the API.{% endblocktrans %} + {% blocktrans %}Each telegram read from your smart meter is stored and queued for processing first.{% endblocktrans %} + {% blocktrans %}Each new telegram is (only) used to display the latest reading, in the top right corner of the Dashboard page.{% endblocktrans %} + +
    @@ -103,6 +112,15 @@ {% trans "Unprocessed telegrams" %}: {{ unprocessed_readings|default:'-' }} + +
    + {% trans "Click for more information" %} + + {% blocktrans %}This indicates how many stored telegrams are waiting to be processed.{% endblocktrans %} + {% blocktrans %}This should reset around each minute mark, depending on whether you've enabled grouping readings in the configuration.{% endblocktrans %} + {% blocktrans %}The stored telegrams are processed by the DSMR_BACKEND process and thus can be processed retroactively as well (by design).{% endblocktrans %} + +
    @@ -144,6 +162,14 @@ {% trans "No data." %} {% endif %} + +
    + {% trans "Click for more information" %} + + {% blocktrans %}When telegrams are processed, they are split into electricity and gas (when available) consumption nodes.{% endblocktrans %} + {% blocktrans %}These consumption nodes are plotted in the graphs displayed on the Dashboard page.{% endblocktrans %} + +
    @@ -172,6 +198,14 @@ {% trans "No data." %} {% endif %} + +
    + {% trans "Click for more information" %} + + {% blocktrans %}When telegrams are processed, they are split into electricity and gas (when available) consumption nodes.{% endblocktrans %} + {% blocktrans %}These consumption nodes are plotted in the graphs displayed on the Dashboard page.{% endblocktrans %} + +
    @@ -207,6 +241,14 @@ {% trans "Electricity usage" %}: {% trans "No data." %} {% endif %} + +
    + {% trans "Click for more information" %} + + {% blocktrans %}The consumption nodes reflect the capabilities of your smart meter.{% endblocktrans %} + {% blocktrans %}The status of each of these (three) capabilities are displayed here and they determine which graphs are rendered in the application pages.{% endblocktrans %} + +
    @@ -226,6 +268,13 @@ {% endif %} +
    + {% trans "Click for more information" %} + + {% blocktrans %}The consumption nodes reflect the capabilities of your smart meter.{% endblocktrans %} + {% blocktrans %}The status of each of these (three) capabilities are displayed here and they determine which graphs are rendered in the application pages.{% endblocktrans %} + +
    @@ -244,6 +293,14 @@ {% trans "Gas usage" %}: {% trans "No data." %} {% endif %} + +
    + {% trans "Click for more information" %} + + {% blocktrans %}The consumption nodes reflect the capabilities of your smart meter.{% endblocktrans %} + {% blocktrans %}The status of each of these (three) capabilities are displayed here and they determine which graphs are rendered in the application pages.{% endblocktrans %} + +
    @@ -268,7 +325,6 @@
      {% trans "Day & hour statistics" %}
    - {% blocktrans %}For day totals, archive and trends. Calculated once a day (few hours after midnight).{% endblocktrans %}
    {% if days_since_latest_day_statistics == None or days_since_latest_day_statistics > 1 %} @@ -283,6 +339,15 @@ {% trans "Data processing is on schedule" %}: {{ latest_day_statistics.day }}
    {% endif %} + +
    + {% trans "Click for more information" %} + + {% blocktrans %}At the end of each day (around 1 a.m.) all consumption nodes will be aggregated to statistics nodes.{% endblocktrans %} + {% blocktrans %}These statistics nodes consist of daily and hourly consumption totals (due to performance).{% endblocktrans %} + {% blocktrans %}They are used in many pages displaying long term data, such as the Archive, Trends and Compare pages.{% endblocktrans %} + +
    @@ -296,11 +361,11 @@