feat: initial scaffold and profiles for Schneider iEM2135, LUG heat meter v4
Auto Tag / tag (push) Failing after 2s
Auto Tag / release (push) Has been skipped
CI / validate (push) Failing after 3s

Seed the repo described in pda-fieldbus ADR-0009: a sibling repo that
ships device profiles independently of the fieldbus binary.

Layout:
- profiles/schneider-iem2135.json    — distilled from the inline extract
                                       rules in examples/poll-d27-g110.yaml
- profiles/lug-heat-meter-v4.json    — heat-meter profile with derived
                                       delta_temperature

Both validate against pda-fieldbus's profile.LoadDirs.

Packaging:
- nfpm.yaml builds pda-fieldbus-profiles.deb installing profiles/ to
  /usr/share/pda-fieldbus/profiles/, where the loader's DirPackaged dir
  picks them up. Recommends pda-fieldbus.
- .gitea/workflows/auto-tag.yml: same conventional-commit auto-tagging
  as pda-fieldbus, on tag push installs nfpm, builds .deb, uploads to
  repo.pda.cz/PDAT/main using the existing PDA_REPO_TOKEN secret.
- .gitea/workflows/ci.yml: JSON syntax check + schema validation by
  importing pda-fieldbus's loader and calling LoadDirs against profiles/.
This commit is contained in:
2026-05-01 13:30:35 +02:00
commit 924b7b5b34
9 changed files with 371 additions and 0 deletions
+96
View File
@@ -0,0 +1,96 @@
name: Auto Tag
on:
push:
branches: [main]
permissions:
contents: write
jobs:
tag:
runs-on: ubuntu-latest
outputs:
new_tag: ${{ steps.bump.outputs.new_tag }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine version bump and create tag
id: bump
run: |
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
echo "Latest tag: $LATEST_TAG"
COMMITS=$(git log "${LATEST_TAG}..HEAD" --pretty=format:"%s" 2>/dev/null)
if [ -z "$COMMITS" ]; then
echo "No new commits since ${LATEST_TAG}, skipping."
exit 0
fi
BUMP=""
if echo "$COMMITS" | grep -qiE "^[a-z]+(\(.+\))?!:|BREAKING CHANGE"; then
BUMP="major"
elif echo "$COMMITS" | grep -qiE "^feat(\(.+\))?:"; then
BUMP="minor"
elif echo "$COMMITS" | grep -qiE "^fix(\(.+\))?:"; then
BUMP="patch"
fi
if [ -z "$BUMP" ]; then
echo "No conventional commit triggers, skipping."
exit 0
fi
VERSION="${LATEST_TAG#v}"
MAJOR=$(echo "$VERSION" | cut -d. -f1)
MINOR=$(echo "$VERSION" | cut -d. -f2)
PATCH=$(echo "$VERSION" | cut -d. -f3)
case "$BUMP" in
major) MAJOR=$((MAJOR + 1)); MINOR=0; PATCH=0 ;;
minor) MINOR=$((MINOR + 1)); PATCH=0 ;;
patch) PATCH=$((PATCH + 1)) ;;
esac
NEW_TAG="v${MAJOR}.${MINOR}.${PATCH}"
echo "Creating tag: $NEW_TAG"
git tag "$NEW_TAG"
git push origin "$NEW_TAG"
echo "new_tag=$NEW_TAG" >> "$GITHUB_OUTPUT"
release:
needs: tag
if: needs.tag.outputs.new_tag != ''
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.tag.outputs.new_tag }}
- uses: actions/setup-go@v5
with:
go-version: "1.25"
cache: false
- name: Install nfpm
run: go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.41.3
- name: Build .deb
run: |
VER="${{ needs.tag.outputs.new_tag }}"
VER="${VER#v}"
mkdir -p dist
VERSION="$VER" nfpm pkg --packager deb --target dist/ -f nfpm.yaml
ls -la dist/
- name: Publish .deb to repo.pda.cz
run: |
for deb in dist/*.deb; do
echo "Uploading $deb"
curl --fail -X POST https://repo.pda.cz/api/v1/PDAT/main/upload \
-H "Authorization: Bearer ${{ secrets.PDA_REPO_TOKEN }}" \
-F "file=@${deb}"
done
+60
View File
@@ -0,0 +1,60 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: "1.25"
cache: false
- name: JSON syntax check
run: |
for f in profiles/*.json; do
echo "checking $f"
python3 -m json.tool "$f" > /dev/null
done
- name: Schema validation via pda-fieldbus loader
working-directory: ${{ runner.temp }}
run: |
mkdir -p validator && cd validator
go mod init validator
go get github.com/pdat-cz/pda-fieldbus@latest
cat > main.go <<'EOF'
package main
import (
"fmt"
"os"
"github.com/pdat-cz/pda-fieldbus/pkg/proto/profile"
)
func main() {
if len(os.Args) != 2 {
fmt.Fprintln(os.Stderr, "usage: validator <profiles-dir>")
os.Exit(2)
}
m, err := profile.LoadDirs(os.Args[1])
if err != nil {
fmt.Fprintln(os.Stderr, "FAIL:", err)
os.Exit(1)
}
for n, p := range m {
fmt.Printf("OK %s device=%s/%s points=%d derived=%d\n",
n, p.Device.Manufacturer, p.Device.Model,
len(p.Points), len(p.Derived))
}
}
EOF
go run . "$GITHUB_WORKSPACE/profiles"
+4
View File
@@ -0,0 +1,4 @@
/dist/
/.cache/
*.deb
*.tar.gz
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 PDA Servers
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.
+12
View File
@@ -0,0 +1,12 @@
VERSION ?= 0.0.0-dev
.PHONY: package clean
# Build a .deb at $(VERSION). Requires nfpm in PATH.
# Example: make package VERSION=0.1.0
package:
mkdir -p dist
VERSION=$(VERSION) nfpm pkg --packager deb --target dist/ -f nfpm.yaml
clean:
rm -rf dist/
+61
View File
@@ -0,0 +1,61 @@
# pda-fieldbus-profiles
Reusable device profiles for [pda-fieldbus](https://git.pda.cz/PDAT/pda-fieldbus).
A device profile is a JSON description of one device model: which
DIF/VIF records to read on M-Bus (or which registers on Modbus), what
units they have, how to scale them, and any derived values to compute
from them. Profiles let `pda-fieldbus poll` configurations stay short
(`profile: schneider-iem2135`) instead of repeating extract rules per
deployment.
See `pda-fieldbus` ADR-0009 and spec PDA-0010 for the full schema and
loader semantics.
## Layout
```
profiles/
schneider-iem2135.json
lug-heat-meter-v4.json
...
```
Each file is one profile. The filename stem is the profile name
referenced from a poll config (`profile: schneider-iem2135`).
## Installation
The `pda-fieldbus-profiles` `.deb` installs files to:
```
/usr/share/pda-fieldbus/profiles/
```
The `pda-fieldbus` loader scans that directory plus
`/etc/pda-fieldbus/profiles.d/` (operator overrides — wins on filename
collision). To override a packaged profile on one box, copy it to the
operator dir and edit there; the package will not overwrite it.
## Adding a profile
1. Create `profiles/<name>.json` following an existing profile.
2. Validate it loads against the current `pda-fieldbus` loader:
```
pda-fieldbus poll --config <some.yaml> --profile-dir ./profiles --dry-run
```
3. Open a PR. Use a `feat:` commit (`feat: add <vendor>-<model> profile`).
The `feat:` prefix triggers a minor version bump and a release of the
`.deb` to repo.pda.cz.
## Conventional commits
Same convention as `pda-fieldbus`:
- `feat:` — new profile (minor bump)
- `fix:` — correction to an existing profile (patch bump)
- `docs:`, `chore:`, `ci:` — no version bump
## License
MIT. See `LICENSE`.
+28
View File
@@ -0,0 +1,28 @@
# nfpm config — package profiles/ as /usr/share/pda-fieldbus/profiles/
# Version is injected at build time:
# nfpm pkg --packager deb --target dist/ -f nfpm.yaml -v "$VERSION"
name: pda-fieldbus-profiles
arch: all
platform: linux
version: ${VERSION}
section: contrib/utils
priority: optional
maintainer: p.d.a. <info@pda.cz>
vendor: p.d.a.
homepage: https://git.pda.cz/PDAT/pda-fieldbus-profiles
license: MIT
description: |
Device profiles for pda-fieldbus.
Reusable JSON descriptions of M-Bus and Modbus device models — points,
units, scaling, and derived values — consumed by pda-fieldbus poll
via `profile: <name>` references.
contents:
- src: profiles/
dst: /usr/share/pda-fieldbus/profiles/
type: tree
deb:
fields:
Recommends: pda-fieldbus
+54
View File
@@ -0,0 +1,54 @@
{
"schema": "pda-fieldbus.profile/v1",
"device": {
"manufacturer": "LUG",
"model": "heat-meter-v4",
"protocol": "mbus"
},
"meta": {
"version": "1"
},
"points": {
"energy": {
"addr": "mbus/dif:0C/vif:0F",
"unit": "gigajoule",
"scale": 1e-9,
"dimensions": "energy",
"description": "Total heat energy"
},
"power": {
"addr": "mbus/dif:0B/vif:2D",
"unit": "kilowatt",
"scale": 0.001,
"dimensions": "power",
"description": "Instantaneous thermal power"
},
"flow_temperature": {
"addr": "mbus/dif:0A/vif:5B",
"unit": "celsius",
"dimensions": "temperature",
"description": "Supply (flow) temperature"
},
"return_temperature": {
"addr": "mbus/dif:0A/vif:5F",
"unit": "celsius",
"dimensions": "temperature",
"description": "Return temperature"
},
"volume_flow": {
"addr": "mbus/dif:0B/vif:3B",
"unit": "cubic_metre_per_hour",
"dimensions": "flow",
"description": "Volumetric flow rate"
}
},
"derived": {
"delta_temperature": {
"function": "sub",
"inputs": ["flow_temperature", "return_temperature"],
"unit": "celsius",
"dimensions": "temperature",
"description": "Flow minus return temperature"
}
}
}
+35
View File
@@ -0,0 +1,35 @@
{
"schema": "pda-fieldbus.profile/v1",
"device": {
"manufacturer": "Schneider Electric",
"model": "iEM2135",
"protocol": "mbus"
},
"meta": {
"version": "1",
"references": [
"Schneider iEM2000 series user manual"
]
},
"points": {
"current": {
"addr": "mbus/dif:05/vif:FD/vife:DC,FF,00",
"unit": "ampere",
"dimensions": "current",
"description": "Total current"
},
"power": {
"addr": "mbus/dif:05/vif:2E",
"unit": "watt",
"dimensions": "power",
"description": "Active power"
},
"energy": {
"addr": "mbus/dif:07/vif:03",
"unit": "kilowatt_hour",
"scale": 0.001,
"dimensions": "energy",
"description": "Total active energy import"
}
}
}