Provides a number of DUIS templates intended for use with DCC Boxed.
The templates originate from the Reference Test Data Set project. Conversion of
the templates from XML
into JSON
is managed by the
duis-parser tool. Further, provides a binding for the
Fuse.js library to easily search the templates, e.g. by GBCS Use
Case, Service Request Variant, Service Request Name.
Tariff data within GB smart metering is complex and directly building a tariff from a template is non-trivial. To help reduce the burden, a tariff builder is provided within this library. See example below.
Developed and tested against node 16
. Install from npm
:
npm i @smartdcc/duis-templates
import { loadTemplates, TemplateDirectory } from '@smartdcc/duis-templates'
const templates: TemplateDirectory = await loadTemplates({})
Or with a logger
specified, which will write a line of text in the case it is
unable to load a template:
const templates = await loadTemplates({ logger: console.log })
Once the templates are loaded, a TemplateDirectory
will be obtained. This is
of the following type:
type TemplateDirectory = Record<string, Template>
The keys
of the directory are tags obtained (i.e. normalised) from the file
names of the templates. For example, a typical meter read has the tag
ECS17b_4.1.1_SINGLE
. This includes the GBCS use case code, the service request
variant and optional additional data (in this case SINGLE
). As these tags are
chosen when the Reference Test Data Set is put together, they are fixed in this
project.
The Template
stored in the dictionary has a number of meta-data items
associated, as well as a the JSON
representation of the template. The
templates is provided in two options, normal
and simplified
- the meaning of
these two options is described in duis-parser. In most (if not
all) cases its recommended to use the simplified
version.
As an example, the Template
for the ECS17b_4.1.1_SINGLE
is as follows when
printed from a Node REPL session. Notice the additional meta-data associated
with the templates, such as serviceReferenceVariant
and gbcsTitle
keys.
> directory['ECS17b_4.1.1_SINGLE']
{
fileName: '/path/to/package/templates/ECS17b_4.1.1_SINGLE_SUCCESS_REQUEST_DUIS.XML',
normal: {
'?xml': { '@_version': '1.0', '@_encoding': 'UTF-8' },
'sr:Request': {
'sr:Header': [Object],
'sr:Body': [Object],
'ds:Signature': [Object],
'@_xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#',
'@_xmlns:sr': 'http://www.dccinterface.co.uk/ServiceUserGateway',
'@_xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'@_schemaVersion': '5.1'
}
},
simplified: {
header: {
type: 'request',
requestId: [Object],
commandVariant: [Object],
serviceReference: '4.1',
serviceReferenceVariant: [Object]
},
body: { ReadInstantaneousImportRegisters: '' }
},
serviceReferenceVariant: {
'Service Request Name': 'Read Instantaneous Import Registers',
'Service Reference': '4.1',
'Service Reference Variant': '4.1.1',
Critical: 'No',
'On Demand': 'Yes',
'Future Dated Response Pattern': 'DSP',
'DCC Scheduled': 'No',
'Non-Device Request': 'No',
'Eligible User Roles': [ 'IS', 'GS', 'ED', 'GT' ]
},
gbcs: 'ECS17b',
gbcsVariant: undefined,
gbcsTitle: 'ECS17b Read ESME Energy Registers (Import Energy)',
info: 'SINGLE'
}
To convert templates back into XML, please see the duis-parser
library as it provides a constructDuis
function. It also provides guidance on
how to sign the XML.
As there are lots of templates, often with slight variants a search feature is provided. This is a light-weight wraparound the Fuse.js with some of the parameters set to useable defaults.
However, as Fuse.js expects the data it searches to be a list instead of a
dictionary, the dictionary is converted into a list using Object.entries
function. The result of this is that the format of the searched data is as
follows:
[
[ tag1, Template1 ],
[ tag2, Template2 ],
[ tag3, Template3 ],
...
]
Thus, in the results of the search, each tag is referenced as 0
and the fields
of the template are prefixed with 1.
.
Below is an example of how to use the search:
import { search } from '@smartdcc/duis-templates'
const fuse = search(directory)
console.log(fuse.search('4.1.1'))
Which could output the following:
[
{
item: [ 'ECS17b_4.1.1_DSP_FUTURE_DATED', [Object] ],
refIndex: 90,
matches: [ [Object], [Object] ]
},
{
item: [ 'ECS17b_4.1.1', [Object] ],
refIndex: 91,
matches: [ [Object], [Object] ]
},
{
item: [ 'ECS17b_4.1.1_SINGLE', [Object] ],
refIndex: 92,
matches: [ [Object], [Object] ]
},
{
item: [ 'ECS17b_4.1.1_TWIN', [Object] ],
refIndex: 93,
matches: [ [Object], [Object] ]
},
{
item: [ 'GCS13a_4.1.1_RELIABLE_GPF', [Object] ],
refIndex: 211,
matches: [ [Object], [Object] ]
},
...
The structure of the result set is described in the Fuse.js documentation. Of
interest, the matches
item shows which key in the Template was matched and the
position in the string too.
It is possible to map a use case code to a textual names directly without the service request. This is exposed as:
import { lookupGBCS } from '@smartdcc/duis-templates'
console.log(lookupGBCS('ECS17b'))
Which might return:
{
'Use Case Name': 'Read Import Energy / Consumption Registers',
'Use Case Title': 'ECS17b Read ESME Energy Registers (Import Energy)',
'Message Type': 'SME.C.NC',
'Use Case Description': 'This Use Case is for reading the ESME import energy registers / GSME consumption registers.',
'Remote Party or HAN Message': 'Remote Party',
'Service Reference': '4.1',
Code: 'ECS17b'
}
The library includes utility functions to help build a service request 1.1.1
-
Update Import Tariff (Primary Element) for an ESME.
This consists of two parts, first a TypeScript definition of a
tariff and then a utility function to
convert this into a DUIS request. They TypeScript definition of a tariff
attempts to be as close as possible to the underlying DUIS request, so an
understanding of service request 1.1.1
is required, which can be found in
dugids.
A simple tariff which is £0.55/day standing charge and £0.20/kWh can be defined as follows:
import { Tariff } from '@smartdcc/duis-parser'
const tariff: Tariff = {
seasons: [
{
name: 'all',
weekProfile: 1
},
],
weekProfiles: [[1, 1, 1, 1, 1, 1, 1]],
dayProfiles: [
[
{
mode: 'tou',
startTime: 0,
action: 1,
},
],
],
specialDays: [],
tous: [20],
blocks: [
{
prices: [0, 0],
thresholds: [ 0],
},
{
prices: [0, 0],
thresholds: [0],
},
{
prices: [0, 0],
thresholds: [0],
},
{
prices: [0, 0],
thresholds: [0],
},
{
prices: [0, 0],
thresholds: [0],
},
{
prices: [0, 0],
thresholds: [0],
},
{
prices: [0, 0],
thresholds: [0],
},
{
prices: [0, 0],
thresholds: [0],
},
],
pricing: {
priceScale: -2,
standingCharge: 55,
standingChargeScale: -2,
},
}
This would then be constructed into a DUIS request as follows:
import {SimplifiedDuisOutputRequest, buildUpdateImportTariff_PrimaryElement} from '@smartdcc/duis-templates'
const req: SimplifiedDuisOutputRequest = buildUpdateImportTariff_PrimaryElement(
simpleToUTariff,
{
counter: BigInt(1006),
originatorId: '90-b3-d5-1f-30-01-00-00',
targetId: '00-db-12-34-56-78-90-a0',
},
)
This can be used in the same way as the templates discussed above.
For more examples of tariffs, see the test script.
Contributions are welcome!
When submitting a pull request, please ensure:
- Each PR is concise and provides only one feature/bug fix.
- Unit test are provided to cover feature. The project uses
jest
. To test, runnpm run test:cov
to view code coverage metrics. - Bugfixes are reference the GitHub issue.
- If appropriate, update documentation.
- Before committing, run
npm run lint
andnpm run prettier-check
.
If you are planning a new non-trivial feature, please first raise a GitHub issue to discuss it to before investing your time to avoid disappointment.
Any contributions will be expected to be licensable under GPLv3.
Copyright 2022, Smart DCC Limited, All rights reserved. Project is licensed under GPLv3.