@deconz-community/ddf-bundler v0.21.0
DDF bundler
General
The format is a Resource Interchange File Format (RIFF), see: https://en.wikipedia.org/wiki/Resource_Interchange_File_Format Which can store arbitrary content and more importantly can by extended easily while being backward compatible.
All multi byte values are little-endian encoded.
DDF_BUNDLE_MAGIC is ASCII "DDFB"
Each chunk is prefixed by it's tag, then the size and finnaly the data.
U32 'RIFF'
U32 RIFF Size
U32 DDF_BUNDLE_MAGIC
U32 DDF_Bundle Size
U32 Chunk Tag
U32 Chunk Size
Data[Size]
....
U32 Chunk Tag
U32 Chunk Size
Data[Size]
The file can be see as a tree structure.
Visual representation of the DDF split by chunks
Chunks
DDFB.DESC - Descriptor - unique
U32 'DESC'
U32 Chunk Size
Data[Size]
This is always the first chunk and allows fast indexing and matching without parsing the whole DDF. It's a JSON file.
{
"source": "https://deconz-community.github.io/ddf-store/XXXX/XXXX",
"last_modified": "2023-01-08T17:24:24z",
"version_deconz": ">2.19.3",
"product": "acme 2000",
"links": [
"url-to-forum-entry",
"url-to-github-entry"
],
"device_identifiers": [
["Philips", "acme 2000"],
["Signify", "acme 200"]
]
}
source (optional)
The URL of the DDF page on the store, could be used to update DDF.
Example
"https://deconz-community.github.io/ddf-store/XXXX/XXXX"
last_modified (required)
The last modified date of the bundle in a complete date plus hours ISO 8601 format.
Example
"2023-01-08T17:24:24z"
version_deconz (required)
The minimum version for Deconz. It's using Semantic Versioning with version comparaison. See Semver Calculator for example.
Example
">2.20.1"
product (required)
The english device commercial name of the device.
Example
"acme 2000"
product_localised (optional)
The device commercial name of the device localised indexed by the ISO 639-1 code.
Note that the "en" name it's on product
property.
Example
{
"de": "german product name",
"fr": "french product name"
}
links (optional)
Any link usefull about this bundle, can be issue link, forum link, device official web page
Example
[
"url-to-forum-entry",
"url-to-github-entry"
]
device_identifiers (required)
The list of device identifier, it's generated from each combinaison of manufacturername
and modelid
from the DDF.
Example
[
["Philips", "acme 2000"],
["Signify", "acme 200"]
]
DDFB.DDFC - DDF JSON (compressed) - unique
U32 'DDFC'
U32 Chunk Size
Data[Size]
Holds the base DDF compressed with zlib.
DDFB.EXTF - External file - multiple
U32 'EXTF'
U32 FileType (see below)
U16 PathLength
U8 [PathLength] filepath
U16 ModificationTimeLength
U8 [ModificationTimeLength] ModificationTime in ISO 8601 format
U32 FileSize
U8 Data[FileSize]
FileType
FileType is a tag to know what kind of file the chunk contain.
For Text file they are all compressed using zlib.
Tag | Description | Data | Format |
---|---|---|---|
SCJS | Javascript file for read, write or parse | Text file | javascript |
JSON | Generic files for items / constants | Text file | json |
BTNM | Button maps* WIP NOT USED | Text file | json |
CHLG | Changelog | Text file | markdown |
NOTI | Informational note | Text file | markdown |
NOTW | Warning note | Text file | markdown |
KWIS | Know issue | Text file | markdown |
IMGP | Image in PNG can be used in UI | Binary | png |
DDFB.VALI - DDF Validation result - unique - optional
The result of the validation using the ddf-validator. It's a JSON object.
If there is no errors the errors
property is omitted.
result
can be success
, error
or skipped
.
Example success
{
"result": "success",
"version": "2.20.0"
}
Example error
{
"result": "error",
"version": "2.20.0",
"errors": [
{
"type": "simple",
"message": "Missing file 'warning.md'."
},
{
"type": "validation",
"message": "Unrecognized key(s) in object: 'cl'",
"path": ["subdevices", 0, "items", 6, "parse"],
"file": "generic/items/state_airquality_item.json",
"line": 40,
"column": 5
},
{
"type": "validation",
"message": "Unrecognized key(s) in object: 'cl'",
"file": "ddf.json",
"path": ["subdevices", 0, "items", 9, "parse"],
"line": 40,
"column": 5
}
]
}
Example skipped
Used when the flag ddfvalidate
is set to false in the DDFC.
{
"result": "skipped",
"version": "2.20.0"
}
SIGN - Signature - multiple
Signatures are very easy to handle with a few lines of code and make sure the DDF is not messed with. A DDF bundle which is submitted for testing can be promoted to stable / official by simply adding another signature in this chunk nothing else needs to be modified.
Holds one signature over the DDF_BUNDLE_MAGIC
chunk. The signature and public key use the secp256k1 ECDSA format.
https://paulmillr.com/noble/
U32 'SIGN'
U32 Chunk Size
U16 PublicKey Length
U8 [PublicKey Length] PublicKey
U16 Signature Length
U8 [Signature Length] Signature
Thoses chunk are always at the end of the bundle and not inside the DDFB chunk.
Example usage
Decoding a bundle
import { decode } from '@deconz-community/ddf-bundler'
import { readFile } from 'fs/promises'
const data = await readFile(path.join(__dirname, 'ddf/aq1_vibration_sensor.ddf'))
const blob = new Blob([data])
blob.name = 'aq1_vibration_sensor.ddf'
const bundle = await decode(blob)
Encoding a bundle
import { Bundle, encode } from '@deconz-community/ddf-bundler'
const bundle = Bundle()
bundle.data.name = 'sample.ddf'
bundle.data.desc.product = 'Sample product'
bundle.data.ddfc = '{"schema": "devcap1.schema.json"}'
bundle.data.files.push({
type: 'JSON',
data: JSON.stringify({ foo: 'bar' }),
path: 'foo.json',
last_modified: new Date(),
})
const encoded = encode(bundle)
Building a bundle from files
import { buildFromFiles, createSource } from '@deconz-community/ddf-bundler'
const bundle = await buildFromFiles(
`file://${genericDirectoryPath}`,
`file://${inputFilePath}`,
async (path) => {
if (sources.has(path))
return sources.get(path)!
const filePath = path.replace('file://', '')
const data = await fs.readFile(filePath)
const source = createSource(new Blob([data]), {
path,
last_modified: (await fs.stat(filePath)).mtime,
})
sources.set(path, source)
return source
},
)
2 days ago
4 days ago
7 days ago
7 days ago
8 days ago
7 days ago
20 days ago
5 months ago
5 months ago
5 months ago
5 months ago
10 months ago
8 months ago
10 months ago
5 months ago
10 months ago
10 months ago
10 months ago
11 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago