diff --git a/.coveragerc b/.coveragerc
deleted file mode 100644
index 10c025fbfa1c5cd9566a1b38d8d442b1494a4208..0000000000000000000000000000000000000000
--- a/.coveragerc
+++ /dev/null
@@ -1,2 +0,0 @@
-[run]
-concurrency=multiprocessing,thread
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a047e435811c03a31e4c65c0d7ca9b7ce8d0cb2a
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 GÉANT Vereniging
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/MANIFEST.in b/MANIFEST.in
index 04932c963ccc3b400e6ff0224f1bb000240226e6..1842a72e0920e258d37be3cfd645fda7a4f9da39 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -2,4 +2,5 @@ include brian_dashboard_manager/logging_default_config.json
 include brian_dashboard_manager/dashboards/*
 include brian_dashboard_manager/datasources/*
 include config.json.example
-recursive-include brian_dashboard_manager/templating/templates *
\ No newline at end of file
+recursive-include brian_dashboard_manager/templating/templates *
+recursive-exclude test *
\ No newline at end of file
diff --git a/brian_dashboard_manager/config.py b/brian_dashboard_manager/config.py
index 3b09bf03a820469594ba41beaca629570182de49..b22ef4e4d11e7ce2764cd9b04ffdfb2f1791685b 100644
--- a/brian_dashboard_manager/config.py
+++ b/brian_dashboard_manager/config.py
@@ -203,7 +203,7 @@ CONFIG_SCHEMA = {
         "datasources": {
             "type": "object",
             "properties": {
-                "influxdb": {"$ref": "#definitions/influx-datasource"}
+                "influxdb": {"$ref": "#/definitions/influx-datasource"}
             },
             "additionalProperties": False
         },
diff --git a/brian_dashboard_manager/templating/helpers.py b/brian_dashboard_manager/templating/helpers.py
index 2e0089a1b535152a7ad2924b81108b01e5299edd..6426eb71d86c0d0f5d29ecb6b3c836407c3ee010 100644
--- a/brian_dashboard_manager/templating/helpers.py
+++ b/brian_dashboard_manager/templating/helpers.py
@@ -231,11 +231,20 @@ def get_nren_interface_data(services, interfaces, excluded_dashboards):
                 # MDVPN type services don't have data in BRIAN
                 continue
 
+            has_v6_interface = False
+            for interface in _interfaces:
+                if 'addresses' in interface:
+                    for address in interface['addresses']:
+                        if address.find(':') > 0:
+                            has_v6_interface = True
+                            break
+
             dashboard['SERVICES'].append({
                 'measurement': measurement,
                 'title': title,
                 'scid': scid,
-                'sort': (sid[:2], name)
+                'sort': (sid[:2], name),
+                'has_v6': has_v6_interface
             })
 
     def _check_in_aggregate(router, interface):
@@ -486,7 +495,7 @@ def get_panel_fields(panel, panel_type, datasource):
     })
 
 
-def default_interface_panel_generator(gridPos):
+def default_interface_panel_generator(gridPos, ipv6_only=False):
     """
     Helper for generating panel definitions for dashboards.
 
@@ -494,6 +503,7 @@ def default_interface_panel_generator(gridPos):
     panel data and panel type.
 
     :param gridPos: generator for grid positions
+    :param ipv6_only: whether to use IPv6 traffic exclusively or not
 
     :return: function that generates panel definitions
     """
@@ -515,20 +525,29 @@ def default_interface_panel_generator(gridPos):
         result = []
 
         for panel in panels:
-            result.append(get_panel_fields({
-                **panel,
-                **next(gridPos)
-            }, 'traffic', datasource))
-            if panel.get('has_v6', False):
-                result.append(get_panel_fields({
-                    **panel,
-                    **next(gridPos)
-                }, 'IPv6', datasource))
-            if errors:
+            if ipv6_only:
+                if panel.get('has_v6', False):
+                    result.append(get_panel_fields({
+                        **panel,
+                        **next(gridPos)
+                    }, 'IPv6', datasource))
+                else:
+                    continue
+            else:
                 result.append(get_panel_fields({
                     **panel,
                     **next(gridPos)
-                }, 'errors', datasource))
+                }, 'traffic', datasource))
+                if panel.get('has_v6', False):
+                    result.append(get_panel_fields({
+                        **panel,
+                        **next(gridPos)
+                    }, 'IPv6', datasource))
+                if errors:
+                    result.append(get_panel_fields({
+                        **panel,
+                        **next(gridPos)
+                    }, 'errors', datasource))
 
         return result
 
@@ -567,6 +586,7 @@ def get_nren_dashboard_data_single(data, datasource, tag):
         agg_panels = []
 
     panel_gen = default_interface_panel_generator(gridPos)
+    panel_ipv6_gen = default_interface_panel_generator(gridPos, ipv6_only=True)
 
     services_dropdown = create_dropdown_panel('Services', **next(gridPos))
 
@@ -578,6 +598,12 @@ def get_nren_dashboard_data_single(data, datasource, tag):
 
     service_panels = panel_gen(
         sorted(dash['SERVICES'], key=sort_key), datasource)
+
+    services_ipv6_dropdown = create_dropdown_panel('Services - IPv6 Only', **next(gridPos))
+    service_ipv6_panels = panel_ipv6_gen(
+        sorted(dash['SERVICES'], key=sort_key), datasource
+    )
+
     iface_dropdown = create_dropdown_panel('Interfaces', **next(gridPos))
     phys_panels = panel_gen(dash['PHYSICAL'], datasource, True)
 
@@ -590,6 +616,10 @@ def get_nren_dashboard_data_single(data, datasource, tag):
                 'dropdown': services_dropdown,
                 'panels': service_panels,
             },
+            {
+                'dropdown': services_ipv6_dropdown,
+                'panels': service_ipv6_panels
+            },
             {
                 'dropdown': iface_dropdown,
                 'panels': phys_panels,
@@ -769,7 +799,7 @@ def get_aggregate_dashboard_data(title, remotes, datasource, tag):
     ingress and one for egress.
 
     :param title: title for the dashboard
-    :param targets: dictionary of targets for the panels, the key is the
+    :param remotes: dictionary of targets for the panels, the key is the
     remote (usually a customer) and the value is a list of targets
     for that remote. A single target represents how to fetch
     data for one interface.
diff --git a/changelog.md b/changelog.md
index daf7df5d8ce05316d8d2f21c63652cefd068ba55..ae6f889ad242271b73c41312a20097bc22475976 100644
--- a/changelog.md
+++ b/changelog.md
@@ -2,6 +2,9 @@
 
 All notable changes to this project will be documented in this file.
 
+## [0.54] - 2023-02-09
+- POL1-648: Added IPv6 graphs for NREN dashboards
+
 ## [0.53] - 2023-06-21
 - Add banner explaining difference between average/mean for >48h time ranges
 
diff --git a/setup.py b/setup.py
index bd93bf37a7dcae0578f7753a98ccfdd975682b73..bdef8ce35787a79235b59199077d9c4b4178f3e7 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
 
 setup(
     name='brian-dashboard-manager',
-    version="0.53",
+    version="0.54",
     author='GEANT',
     author_email='swd@geant.org',
     description='',
@@ -16,4 +16,6 @@ setup(
         'sentry-sdk[flask]'
     ],
     include_package_data=True,
+    license='MIT',
+    license_files=('LICENSE.txt',)
 )
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/test/test_gws_direct.py b/test/test_gws_direct.py
index 5ff611024caa768619263c39cecc828d7eecb675..0a263c0f33a2c07ae2ec3fcd4c98020c42c1ca78 100644
--- a/test/test_gws_direct.py
+++ b/test/test_gws_direct.py
@@ -1,5 +1,5 @@
 import responses
-from conftest import get_test_data
+from test.conftest import get_test_data
 from brian_dashboard_manager.templating.gws import generate_gws
 from brian_dashboard_manager.inventory_provider.interfaces import \
     get_gws_direct
diff --git a/test/test_update.py b/test/test_update.py
index 55df28bd65daa4c56e2ff9d4e1597db4fb79b1d1..57b09f2057e5dfb234d0de0d59d8749d05104c7e 100644
--- a/test/test_update.py
+++ b/test/test_update.py
@@ -3,7 +3,7 @@ import json
 
 from brian_dashboard_manager.grafana.provision import provision_folder, \
     provision
-from conftest import get_test_data
+from test.conftest import get_test_data
 
 TEST_INTERFACES = [
     {
diff --git a/tox.ini b/tox.ini
index f2c726d273badaeac99d80aa1b1ca0736b1422dd..dc78bc46551ca55171192633bc42e0c3eaaa935f 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,24 +1,22 @@
 [tox]
-envlist = py36
+envlist = py38, py311
 
 [flake8]
 exclude = venv,.tox
 max-line-length = 120
 
+[coverage:run]
+concurrency = multiprocessing,thread
+
 [testenv]
-setenv = 
-    COVERAGE_PROCESS_START=.coveragerc
 deps =
-    coverage
+    pytest-xdist
+    pytest-cov
     flake8
     -r requirements.txt
 
 commands =
     coverage erase
-    coverage run --source brian_dashboard_manager -m pytest {posargs}
-    coverage combine
-    coverage xml
-    coverage html
-    coverage report --fail-under 75
+    pytest -n auto --cov brian_dashboard_manager --cov-fail-under=80 --cov-report html --cov-report xml --cov-report term -p no:checkdocs
     flake8
     sphinx-build -M html docs/source docs/build