kopia lustrzana https://github.com/weetmuts/wmbusmeters
Porównaj commity
167 Commity
1.14.0-RC1
...
master
Autor | SHA1 | Data |
---|---|---|
Fredrik Öhrström | 1a4169ed23 | |
PovilasID | aa4f1956e8 | |
Fredrik Öhrström | d90dbb196e | |
Fredrik Öhrström | 14d021426a | |
Michał Morański | f32179a939 | |
Fredrik Öhrström | a32fcfdf9a | |
Fredrik Öhrström | efcc41d107 | |
Fredrik Öhrström | a69e547a17 | |
Fredrik Öhrström | 23f2279a64 | |
Fredrik Öhrström | 05edab0882 | |
Fredrik Öhrström | ff72e1debc | |
Fredrik Öhrström | c1509f6139 | |
Fredrik Öhrström | 9facddf019 | |
Fredrik Öhrström | 9a34a55abb | |
Fredrik Öhrström | 465a450a8b | |
Jean-Samuel REYNAUD | 9576550f85 | |
Fredrik Öhrström | 1f2cd10160 | |
Fredrik Öhrström | 8c09f7b2d8 | |
Fredrik Öhrström | 3247a4a576 | |
Fredrik Öhrström | 23779cb9f7 | |
Fredrik Öhrström | 5962e727ff | |
Arthur van Dorp | 03d95e780e | |
Fredrik Öhrström | 11c83c1f37 | |
Fredrik Öhrström | 7634b95438 | |
Fredrik Öhrström | 78e7c47503 | |
Fredrik Öhrström | 0c98b474bb | |
Fredrik Öhrström | 9d27ab3fb3 | |
Fredrik Öhrström | c21efd1d69 | |
testuser7 | 67230b4213 | |
Fredrik Öhrström | 569efa3af2 | |
Fredrik Öhrström | 58dd9d32ff | |
testuser7 | 7f7f7e4df4 | |
Fredrik Öhrström | af83f15ca9 | |
Fredrik Öhrström | 0587c6d1dd | |
Jean-Samuel Reynaud | dd45c14970 | |
Fredrik Öhrström | 097f91fac0 | |
Fredrik Öhrström | dbd99698b8 | |
Fredrik Öhrström | 40605ebb40 | |
Fredrik Öhrström | 74e6c89af1 | |
testuser7 | 4634431c59 | |
Fredrik Öhrström | c3d1b6f3c5 | |
Fredrik Öhrström | 4b55407aa9 | |
testuser7 | 97f2082dbc | |
testuser7 | a5f4f43375 | |
testuser7 | 000e4f89ad | |
Fredrik Öhrström | 14ca481c63 | |
Fredrik Öhrström | 0d0338c9a4 | |
Fredrik Öhrström | 4d3e306f30 | |
Fredrik Öhrström | 378c367475 | |
Fredrik Öhrström | 004d8b751f | |
Fredrik Öhrström | 72ecb86b91 | |
Fredrik Öhrström | 24b47fbd48 | |
Fredrik Öhrström | 8efad28289 | |
Fredrik Öhrström | 46fc3995bd | |
Fredrik Öhrström | 9b6c84d2f2 | |
Fredrik Öhrström | 54a8930918 | |
Fredrik Öhrström | f446efa11d | |
Fredrik Öhrström | 2610af43b8 | |
Fredrik Öhrström | fefbf507fe | |
Fredrik Öhrström | 04ed4d7628 | |
Fredrik Öhrström | 440ea263b1 | |
Fredrik Öhrström | 8aabcdaca0 | |
Fredrik Öhrström | a9862be62c | |
dependabot[bot] | 4d89d119da | |
dependabot[bot] | eea8307f22 | |
Fredrik Öhrström | 03e03905ec | |
Fredrik Öhrström | fe04152246 | |
BIBO | f33a676dee | |
Fredrik Öhrström | 12cb6c9d17 | |
Petr Švarc | 6641def49f | |
Fredrik Öhrström | 3d1319bd78 | |
Fredrik Öhrström | 1ab3368b8c | |
Fredrik Öhrström | b6b6fe85d0 | |
Fredrik Öhrström | b49309bce3 | |
Fredrik Öhrström | 42511190e7 | |
Fredrik Öhrström | 4f21c04804 | |
Fredrik Öhrström | 9a0a818fee | |
Fredrik Öhrström | abad0c8d74 | |
Fredrik Öhrström | 704e715582 | |
Fredrik Öhrström | 866df740ad | |
Andreas Horrer | cbc422ac94 | |
Fredrik Öhrström | 295053ebd6 | |
Fredrik Öhrström | b6878b503c | |
Fredrik Öhrström | 7af4db244d | |
Fredrik Öhrström | fd0a4b6d63 | |
Fredrik Öhrström | cddcc9ae26 | |
Fredrik Öhrström | c08bf05521 | |
Andreas Horrer | 757b56d2c8 | |
Andreas Horrer | f69f9d6aa7 | |
Andreas Horrer | dd2df53280 | |
BIBO | dc783e1e87 | |
dependabot[bot] | d22701f978 | |
Fredrik Öhrström | 331c5a4018 | |
Fredrik Öhrström | 73bb7ef096 | |
Fredrik Öhrström | 10fbac056b | |
Fredrik Öhrström | aff37db2c1 | |
Fredrik Öhrström | b011505d7b | |
Fredrik Öhrström | b0cb4fa44b | |
Fredrik Öhrström | 044a522399 | |
Fredrik Öhrström | 47f3256a50 | |
Fredrik Öhrström | 0c3fa02d4f | |
Fredrik Öhrström | 8077791846 | |
Fredrik Öhrström | 2605ff9cb3 | |
pimlie | 6a9cfcee21 | |
pimlie | efea401f6a | |
pimlie | 4c194ba802 | |
pimlie | db37acbcdc | |
Jacman777 | 92fb04e246 | |
Fredrik Öhrström | b32236f600 | |
Sergio Catalan | 64602a079f | |
Fredrik Öhrström | 162658a29a | |
Fredrik Öhrström | 9fbb49b0fc | |
Fredrik Öhrström | 82234acd21 | |
Fredrik Öhrström | c4b9f0d104 | |
Fredrik Öhrström | 9a99daf0ed | |
Fredrik Öhrström | 3696118db1 | |
Fredrik Öhrström | 92090073cb | |
Fredrik Öhrström | c5dc2ada51 | |
Andreas Horrer | f4299e2d6f | |
Fredrik Öhrström | a385737984 | |
Fredrik Öhrström | 22d6880385 | |
Fredrik Öhrström | b9306be914 | |
Fredrik Öhrström | 3a097388f5 | |
Fredrik Öhrström | b2dd2801db | |
Fredrik Öhrström | 6f0773ae7a | |
Fredrik Öhrström | 128aa77b78 | |
Fredrik Öhrström | 872bc53ace | |
Fredrik Öhrström | a1f0911a57 | |
Fredrik Öhrström | f017694d78 | |
Fredrik Öhrström | 6e3bac97d4 | |
simonr-de | 7c5949d6b1 | |
geraldhuber | eb6311fec3 | |
Fredrik Öhrström | ce6e2822e5 | |
Fredrik Öhrström | eb9c90bd2d | |
Fredrik Öhrström | a8040e5eae | |
Fredrik Öhrström | 099fc1472c | |
Fredrik Öhrström | c6d0b79984 | |
dependabot[bot] | 3c7b37a14b | |
dependabot[bot] | 143f4f2ff0 | |
dependabot[bot] | bc90cf36d3 | |
dependabot[bot] | 108712be3b | |
dependabot[bot] | c4a4d05e46 | |
Fredrik Öhrström | 239a39de0e | |
dependabot[bot] | be3c413664 | |
Fredrik Öhrström | 0b852fb420 | |
Fredrik Öhrström | 9084a0323f | |
Fredrik Öhrström | e577c0b30c | |
Fredrik Öhrström | 71fe4b4392 | |
Fredrik Öhrström | 94d4ddce16 | |
Fredrik Öhrström | 86ba358c7d | |
Fredrik Öhrström | 906c288298 | |
Fredrik Öhrström | a920e25d45 | |
Fredrik Öhrström | 414e55a17a | |
Fredrik Öhrström | 1faabb7526 | |
Fredrik Öhrström | a41bce1145 | |
Fredrik Öhrström | d0f9ffc820 | |
Fredrik Öhrström | b8ac245aeb | |
Fredrik Öhrström | b368647c73 | |
Fredrik Öhrström | 81505354fc | |
Fredrik Öhrström | bd0747eefe | |
PovilasID | c43b8da2bf | |
Fredrik Öhrström | 765f38cdc4 | |
Chris Bednarczyk | 1c960475ca | |
Chris Bednarczyk | 95a4e15baa | |
Chris Bednarczyk | f7b70e4c64 | |
Fredrik Öhrström | 217f0a25fe | |
Fredrik Öhrström | ab9d612b63 |
|
@ -7,12 +7,12 @@ jobs:
|
|||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- id: INSTALL_ADDITIONAL_BUILD_DEPENDENCIES
|
||||
run: |
|
||||
sudo apt install -y eatmydata
|
||||
sudo eatmydata apt install -y devscripts debhelper
|
||||
sudo eatmydata apt build-dep -y . || sudo eatmydata apt install -y librtlsdr-dev adduser
|
||||
sudo eatmydata apt build-dep -y . || sudo eatmydata apt install -y librtlsdr-dev libxml2-dev libxslt1-dev adduser
|
||||
- id: PREPARE_SOURCE
|
||||
run: |
|
||||
ln -s deb debian
|
||||
|
|
|
@ -8,56 +8,111 @@ on:
|
|||
- '[0-9]+\.[0-9]+\.[0-9]+'
|
||||
- '[0-9]+\.[0-9]+\.[0-9]+-RC[0-9]+'
|
||||
|
||||
env:
|
||||
DOCKERHUB_IMAGE: ${{ github.repository }}
|
||||
IMAGE_TAG: |
|
||||
${{ github.ref_type == 'tag' && format('{0}-{1}', (contains(github.ref_name, '-RC') &&
|
||||
'candidate' || 'release'), github.ref_name) || 'latest' }}
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/arm/v7
|
||||
- linux/arm64
|
||||
steps:
|
||||
-
|
||||
name: Prepare
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: wmbusmeters/wmbusmeters
|
||||
tags: type=ref,event=tag
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
tags: |
|
||||
${{ env.IMAGE_TAG }}
|
||||
images: |
|
||||
${{ env.DOCKERHUB_IMAGE }}
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PAT }}
|
||||
-
|
||||
name: Build and push not tagged release
|
||||
if: ${{ !steps.meta.outputs.tags }}
|
||||
uses: docker/build-push-action@v4
|
||||
name: Build and push
|
||||
uses: docker/build-push-action@v5
|
||||
id: docker_build
|
||||
with:
|
||||
context: docker/
|
||||
platforms: linux/amd64,linux/arm64,linux/armhf
|
||||
push: true
|
||||
tags: wmbusmeters/wmbusmeters:latest
|
||||
platforms: ${{ matrix.platform }}
|
||||
provenance: false
|
||||
outputs: |
|
||||
type=image,name=${{ env.DOCKERHUB_IMAGE }},push-by-digest=true,name-canonical=true,push=true
|
||||
-
|
||||
name: Build and push candidate
|
||||
if: ${{ steps.meta.outputs.tags && contains(steps.meta.outputs.tags, '-RC') }}
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: docker/
|
||||
platforms: linux/amd64,linux/arm64,linux/armhf
|
||||
push: true
|
||||
tags: wmbusmeters/wmbusmeters:candidate-${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
|
||||
name: Export digest
|
||||
run: |
|
||||
mkdir -p /tmp/digests
|
||||
digest="${{ steps.docker_build.outputs.digest }}"
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
-
|
||||
name: Build and push tagged release
|
||||
if: ${{ steps.meta.outputs.tags && !contains(steps.meta.outputs.tags, '-RC') }}
|
||||
uses: docker/build-push-action@v4
|
||||
name: Upload digest
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
context: docker/
|
||||
platforms: linux/amd64,linux/arm64,linux/armhf
|
||||
push: true
|
||||
tags: wmbusmeters/wmbusmeters:release-${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
merge:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- build
|
||||
steps:
|
||||
-
|
||||
name: Download digests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
-
|
||||
name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
tags: |
|
||||
${{ env.IMAGE_TAG }}
|
||||
images: |
|
||||
${{ env.DOCKERHUB_IMAGE }}
|
||||
-
|
||||
name: Login to DockerHub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PAT }}
|
||||
-
|
||||
name: Create manifest list and push
|
||||
working-directory: /tmp/digests
|
||||
run: |
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
$(printf '${{ env.DOCKERHUB_IMAGE }}@sha256:%s ' *)
|
||||
-
|
||||
name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ${{ env.DOCKERHUB_IMAGE }}:${{ steps.meta.outputs.version }}
|
|
@ -7,7 +7,7 @@ jobs:
|
|||
build:
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- id: INSTALL_ADDITIONAL_BUILD_DEPENDENCIES
|
||||
run: brew install librtlsdr libusb
|
||||
- id: CONFIGURE
|
||||
|
|
|
@ -20,14 +20,14 @@ jobs:
|
|||
steps:
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
-
|
||||
name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: wmbusmeters/wmbusmeters
|
||||
tags: type=ref,event=tag
|
||||
|
|
|
@ -7,11 +7,11 @@ jobs:
|
|||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- id: INSTALL_ADDITIONAL_BUILD_DEPENDENCIES
|
||||
run: |
|
||||
sudo apt install -y eatmydata
|
||||
sudo eatmydata apt-get install librtlsdr-dev libusb-dev
|
||||
sudo eatmydata apt-get install librtlsdr-dev libusb-dev libxml2-dev libxslt1-dev
|
||||
- id: CONFIGURE
|
||||
run: eatmydata ./configure
|
||||
- id: MAKE
|
||||
|
|
|
@ -10,13 +10,13 @@ jobs:
|
|||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
stale-issue-message: 'This issue is stale because it has been open for 2 month with no activity. Remove stale label or comment or this will be closed in 1 month.'
|
||||
close-issue-message: 'This issue was closed because it has been stalled for 1 month with no activity.'
|
||||
days-before-stale: 60
|
||||
days-before-close: 30
|
||||
operations-per-run: 1000
|
||||
exempt-issue-labels: 'enhancement, Work in progress, Planned'
|
||||
exempt-issue-labels: 'enhancement, work in progress, planned, keep open'
|
||||
days-before-pr-stale: -1
|
||||
days-before-pr-close: -1
|
||||
|
|
|
@ -10,9 +10,9 @@ jobs:
|
|||
dockerHubDescription:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Docker Hub Description
|
||||
uses: peter-evans/dockerhub-description@v3
|
||||
uses: peter-evans/dockerhub-description@v4
|
||||
env:
|
||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PAT }}
|
||||
|
|
|
@ -12,7 +12,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
- run: git fetch --prune --unshallow
|
||||
|
||||
- name: Get wmbusmeters version
|
||||
|
@ -28,7 +28,7 @@ jobs:
|
|||
|
||||
- name: Trigger build for edge release
|
||||
if: ${{ github.ref_name == 'master' }}
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
token: ${{ secrets.HA_PAT }}
|
||||
repository: wmbusmeters/wmbusmeters-ha-addon
|
||||
|
@ -37,7 +37,7 @@ jobs:
|
|||
|
||||
- name: Trigger build for stable release
|
||||
if: ${{ github.ref_name != 'master' }}
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
token: ${{ secrets.HA_PAT }}
|
||||
repository: wmbusmeters/wmbusmeters-ha-addon
|
||||
|
|
|
@ -6,6 +6,7 @@ packaging/
|
|||
testaes/
|
||||
testoutput/
|
||||
tests_tmp/
|
||||
3rdparty/
|
||||
*~
|
||||
config.log
|
||||
autom4te.cache/
|
||||
|
|
97
CHANGES
97
CHANGES
|
@ -1,5 +1,100 @@
|
|||
Version 1.14.0-RC1 2023-07-02
|
||||
|
||||
Fixed long standing confusion wether the DIF binary values are by
|
||||
default signed or unsigned. It turns out that they are signed!
|
||||
Thank you Mathias (Zeppelin500) and KaVauA for sorting this out!
|
||||
|
||||
For unknown VIFS and non-compliant meters the signedness
|
||||
can be overriden to unsigned.
|
||||
|
||||
New improved address specification. E.g. use 12345678.M=KAM.V=1b.T=16
|
||||
to listen to exactly the telegrams with id 12345678 manufacturer KAM,
|
||||
version 0x1b and type 0x16. You if you do not specify any M,V or T, they
|
||||
become wildcards which will be the old default behaviour.
|
||||
|
||||
If you receive multiple telegram versions from the same id, and you want to
|
||||
filter out some versions, do: 12345678,!12345678.V=77
|
||||
|
||||
You can now specify p0 to p250, to read from an mbus using the primary address.
|
||||
E.g. wmbusmeters --pollinterval=5s /dev/ttyUSB1:mbus:2400 TEMP piigth:mbus p0 NOKEY
|
||||
|
||||
Added option --identitymode=(id|id-mfct|full|none) to specify how
|
||||
wmbusmeters groups meter state when receiving telegrams.
|
||||
|
||||
The default (which is the same as before) is to map state based only on id.
|
||||
This usually works ok, however if you have two meters with the same id, but
|
||||
from different manufacturers, you must separate their state with --identitymode=id-mfct
|
||||
Full takes into account version and type as well. None means do not separate state
|
||||
at all, used with wildcards and meters that do not need to keep state, ie all info
|
||||
is in every telegram.
|
||||
|
||||
Version 1.16.1 2024-02-22
|
||||
|
||||
Fix docker file generation.
|
||||
|
||||
Version 1.16.0 2024-02-22
|
||||
|
||||
New build to trigger proper docker versioning.
|
||||
|
||||
Version 1.15.0 2024-02-14
|
||||
Version 1.15.0-RC2 2024-02-14
|
||||
|
||||
Update wmbusmeters-ha-addon with new dockerfile.
|
||||
|
||||
Version 1.15.0-RC1 2024-02-13
|
||||
|
||||
For the daemon you can now drop a driver file (such as iperl.xmq) in /etc/wmbusmeters.driver.d
|
||||
and it will automatically be used (overriding any builtin iperl driver).
|
||||
|
||||
From the command line you can also load a driver file with --driver=file.xmq
|
||||
or load a whole directory with --driverdir=/drivers or in a tuple just use
|
||||
a file name ending with xmq. E.g. "Water driver.xmq 12345678 NOKEY"
|
||||
|
||||
The two first builtin text drivers are elster and iperl.
|
||||
|
||||
ATTENTION! Wmbusmeters now use new -f option when starting rtl_wmbus. There is a
|
||||
warning if rtl_wmbus does not support the -f option and an upgrade is recommended.
|
||||
This option will cause rtl_wmbus to exit with an error if the rtl_sdr dongle stops sending data.
|
||||
This in turn will cause wmbusmeters to restart the pipeline.
|
||||
|
||||
Up till now, the stderr from rtl_sdr has been sent to /dev/null. This is a problem
|
||||
since we cannot see any errors from rtl_sdr that could have caused it to stall.
|
||||
|
||||
However the reason for /dev/null was this bug in rtl_sdr.
|
||||
https://github.com/osmocom/rtl-sdr/commit/142325a93c6ad70f851f43434acfdf75e12dfe03
|
||||
which prevented us from sending the rtl_sdr stderr to wmbusmeters.
|
||||
If we did, rtl_sdr went into a 100% cpu hang when we restarted a wmbusmeters daemon.
|
||||
|
||||
A temporary workaround has been found that both sends the stderr output to wmbusmeters
|
||||
and permits the restart of the daemon. Stderr from rtl_sdr is now sent to
|
||||
/tmp/tmp.XXXXXXX_wmbusmeters_rtlsdr and then tailed into wmbusmeters.
|
||||
This is a temporary solution until the real rtl_sdr bugfix has propagated into enough distributions.
|
||||
|
||||
Add second extension energy MWh VIF 7b00-7b01.
|
||||
|
||||
Sunflowerenergias improved the iwmtx5 driver! Thanks Sunflowerenergias!
|
||||
|
||||
Jacman777 improved the kamheat driver! Thanks Jacman777!
|
||||
|
||||
Pim added a --metershell setting which will invoke a shell command line
|
||||
when a meter is seen for the first time. This can be used to trigger extra
|
||||
commands in HA and other systems, to add the new meter. Thanks Pim!
|
||||
|
||||
Pim added support for the Lansen repeater which sends its own status messages!
|
||||
Pim also fixed a small typo in the human readable date timestamp format!
|
||||
Thanks Pim!
|
||||
|
||||
ATTENTION! The hydrus driver could report the wrong value for total_at_date_m3
|
||||
if an at_date had not been reached yet. This is fixed.
|
||||
|
||||
Added initial support for drivers that can be loaded from config files.
|
||||
Properly receive telegrams from amb8465 which is in command mode.
|
||||
Chris Bednarczyk improved the build process for Darwin/MacOS platform. Thanks Chris!
|
||||
PovilasID added another Hydrodigit version. Thanks PovilasID!
|
||||
Added new units for phase angle: deg rad.
|
||||
Added more fields to the abbb23.
|
||||
|
||||
Version 1.14.0 2023-07-02
|
||||
Version 1.14.0-RC1 2023-07-02
|
||||
|
||||
Added more fields to em24 driver.
|
||||
Added another mfct/type/version combo to em42 driver and the power_kw field.
|
||||
|
|
39
Makefile
39
Makefile
|
@ -1,4 +1,4 @@
|
|||
# Copyright (C) 2017-2023 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
# Copyright (C) 2017-2024 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -138,16 +138,27 @@ ifeq ($(shell uname -s),FreeBSD)
|
|||
USBLIB = -lusb
|
||||
endif
|
||||
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
CXXFLAGS += -I$(shell brew --prefix)/include
|
||||
LDFLAGS += -L$(shell brew --prefix)/lib
|
||||
endif
|
||||
|
||||
$(BUILD)/%.o: src/%.cc $(wildcard src/%.h)
|
||||
$(CXX) $(CXXFLAGS) $< -c -E > $@.src
|
||||
$(CXX) $(CXXFLAGS) $< -MMD -c -o $@
|
||||
|
||||
$(BUILD)/%.o: src/%.c $(wildcard src/%.h)
|
||||
$(CXX) -I/usr/include/libxml2 $(CXXFLAGS) $< -c -E > $@.src
|
||||
$(CXX) -I/usr/include/libxml2 -fpermissive $(CXXFLAGS) $< -MMD -c -o $@
|
||||
|
||||
PROG_OBJS:=\
|
||||
$(BUILD)/address.o \
|
||||
$(BUILD)/aes.o \
|
||||
$(BUILD)/aescmac.o \
|
||||
$(BUILD)/bus.o \
|
||||
$(BUILD)/cmdline.o \
|
||||
$(BUILD)/config.o \
|
||||
$(BUILD)/drivers.o \
|
||||
$(BUILD)/dvparser.o \
|
||||
$(BUILD)/formula.o \
|
||||
$(BUILD)/mbus_rawtty.o \
|
||||
|
@ -173,6 +184,7 @@ PROG_OBJS:=\
|
|||
$(BUILD)/wmbus_rawtty.o \
|
||||
$(BUILD)/wmbus_rc1180.o \
|
||||
$(BUILD)/wmbus_utils.o \
|
||||
$(BUILD)/xmq.o \
|
||||
$(BUILD)/lora_iu880b.o \
|
||||
|
||||
# If you run: "make DRIVER=minomess" then only driver_minomess.cc will be compiled into wmbusmeters.
|
||||
|
@ -182,7 +194,7 @@ ifeq ($(DRIVER),)
|
|||
DRIVER_OBJS:=$(wildcard src/meter_*.cc) $(wildcard src/driver_*.cc)
|
||||
else
|
||||
$(info Building a single driver $(DRIVER))
|
||||
DRIVER_OBJS:=src/driver_auto.cc src/driver_unknown.cc $(wildcard src/meter_*.cc) src/driver_$(DRIVER).cc
|
||||
DRIVER_OBJS:=src/driver_auto.cc src/driver_unknown.cc src/driver_dynamic.cc $(wildcard src/meter_*.cc) src/driver_$(DRIVER).cc
|
||||
endif
|
||||
DRIVER_OBJS:=$(patsubst src/%.cc,$(BUILD)/%.o,$(DRIVER_OBJS))
|
||||
|
||||
|
@ -250,7 +262,7 @@ $(BUILD)/authors.h:
|
|||
|
||||
# Build binary with debug information. ~15M size binary.
|
||||
$(BUILD)/wmbusmeters.g: $(PROG_OBJS) $(DRIVER_OBJS) $(BUILD)/main.o $(BUILD)/short_manual.h
|
||||
$(CXX) -o $(BUILD)/wmbusmeters.g $(PROG_OBJS) $(DRIVER_OBJS) $(BUILD)/main.o $(LDFLAGS) -lrtlsdr $(USBLIB) -lpthread
|
||||
$(CXX) -o $(BUILD)/wmbusmeters.g $(PROG_OBJS) $(DRIVER_OBJS) $(BUILD)/main.o $(LDFLAGS) -lrtlsdr -lxml2 $(USBLIB) -lpthread
|
||||
|
||||
# Production build will have debug information stripped. ~1.5M size binary.
|
||||
# DEBUG=true builds, which has address sanitizer code, will always keep the debug information.
|
||||
|
@ -273,10 +285,10 @@ testinternals: $(BUILD)/testinternals
|
|||
$(BUILD)/testinternals.o: $(PROG_OBJS) $(DRIVER_OBJS) $(wildcard src/*.h)
|
||||
|
||||
$(BUILD)/testinternals: $(BUILD)/testinternals.o
|
||||
$(CXX) -o $(BUILD)/testinternals $(PROG_OBJS) $(DRIVER_OBJS) $(BUILD)/testinternals.o $(LDFLAGS) -lrtlsdr $(USBLIB) -lpthread
|
||||
$(CXX) -o $(BUILD)/testinternals $(PROG_OBJS) $(DRIVER_OBJS) $(BUILD)/testinternals.o $(LDFLAGS) -lrtlsdr -lxml2 $(USBLIB) -lpthread
|
||||
|
||||
$(BUILD)/fuzz: $(PROG_OBJS) $(DRIVER_OBJS) $(BUILD)/fuzz.o
|
||||
$(CXX) -o $(BUILD)/fuzz $(PROG_OBJS) $(DRIVER_OBJS) $(BUILD)/fuzz.o $(LDFLAGS) -lrtlsdr -lpthread
|
||||
$(CXX) -o $(BUILD)/fuzz $(PROG_OBJS) $(DRIVER_OBJS) $(BUILD)/fuzz.o $(LDFLAGS) -lrtlsdr -lxml2 -lpthread
|
||||
|
||||
clean_executables:
|
||||
rm -rf build/wmbusmeters* build_arm/wmbusmeters* build_debug/wmbusmeters* build_arm_debug/wmbusmeters* *~
|
||||
|
@ -313,16 +325,16 @@ lcov:
|
|||
(cd build_debug; genhtml lcov.info)
|
||||
xdg-open build_debug/src/index.html
|
||||
|
||||
test:
|
||||
test: build/xmq
|
||||
@./test.sh build/wmbusmeters
|
||||
|
||||
testd:
|
||||
testd: build/xmq
|
||||
@./test.sh build_debug/wmbusmeters
|
||||
|
||||
testdriver:
|
||||
testdriver: build/xmq
|
||||
@./tests/test_drivers.sh build/wmbusmeters driver_${DRIVER}.cc
|
||||
|
||||
testdriverd:
|
||||
testdriverd: build/xmq
|
||||
@./tests/test_drivers.sh build_debug/wmbusmeters driver_${DRIVER}.cc
|
||||
|
||||
update_manufacturers:
|
||||
|
@ -441,6 +453,15 @@ deploy:
|
|||
collect_copyrights:
|
||||
./scripts/collect_copyrights.sh deb/copyright
|
||||
|
||||
3rdparty/xmq/build/default/release/xmq: $(wildcard 3rdparty/xmq/src/main/c/* 3rdparty/xmq/src/main/c/parts/*)
|
||||
@mkdir -p 3rdparty
|
||||
@(cd 3rdparty; git clone --depth 1 https://github.com/libxmq/xmq.git; cd xmq; ./configure)
|
||||
@cat 3rdparty/xmq/build/default/spec.mk
|
||||
@if [ "$$(cat 3rdparty/xmq/build/default/spec.mk | grep CC)" = "CC:=gcc" ]; then (cd 3rdparty/xmq; make VERBOSE=) ; else rm -f $@ ; mkdir -p $$(dirname $@); touch $@ ; echo "Could not build xmq." ; fi
|
||||
|
||||
build/xmq: 3rdparty/xmq/build/default/release/xmq
|
||||
@cp $< $@
|
||||
|
||||
# Include dependency information generated by gcc in a previous compile.
|
||||
include $(wildcard $(patsubst %.o,%.d,$(PROG_OBJS) $(DRIVER_OBJS)))
|
||||
|
||||
|
|
89
README.md
89
README.md
|
@ -6,6 +6,33 @@ wireless wm-bus meters. The readings can then be published using
|
|||
MQTT, curled to a REST api, inserted into a database or stored in a
|
||||
log file.
|
||||
|
||||
# What does it do?
|
||||
|
||||
Wmbusmeters converts incoming telegrams from (w)mbus/OMS compatible meters like:
|
||||
`1844AE4C4455223368077A55000000_041389E20100023B0000`
|
||||
|
||||
into human readable:
|
||||
`MyTapWater 33225544 123.529 m³ 0 m³/h 2024-03-03 19:36:22`
|
||||
|
||||
or into csv:
|
||||
`MyTapWater;33225544;123.529;0;2024-03-03 19:36:45`
|
||||
|
||||
or into json:
|
||||
```json
|
||||
{
|
||||
"media":"water",
|
||||
"meter":"iperl",
|
||||
"name":"MyTapWater",
|
||||
"id":"33225544",
|
||||
"max_flow_m3h":0,
|
||||
"total_m3":123.529,
|
||||
"timestamp":"2024-03-03T18:37:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
Wmbusmeters can collect telegrams from radio using hardware dongles or rtl-sdr software radio dongles,
|
||||
or from m-bus meters using serial ports, or from files/pipes.
|
||||
|
||||
[FAQ/WIKI/MANUAL pages](https://wmbusmeters.github.io/wmbusmeters-wiki/)
|
||||
|
||||
The program runs on GNU/Linux, MacOSX, FreeBSD, and Raspberry Pi.
|
||||
|
@ -64,6 +91,11 @@ wmbus dongles when wmbusmeters startup.
|
|||
If the serial device (ttyUSB0) might change you can also use `device=im871a:c1,t1`
|
||||
which will probe all serial devices but only scans for im871a which also speeds it up.
|
||||
|
||||
Note that the rtl-sdr devices are not found under the tty devices (e.g. `/dev/tty...`).
|
||||
Instead the rtl-sdr devices are accessed through character device special files named `/dev/swradio0` to `/dev/swradio255`[^kernel_docs_sdr]. Wmbusmeters uses librtsldr to probe these devices.
|
||||
|
||||
[^kernel_docs_sdr]: https://docs.kernel.org/userspace-api/media/v4l/dev-sdr.html?highlight=sdr#software-defined-radio-interface-sdr
|
||||
|
||||
If you have to scan serial devices, then remember that some Raspberry PIs are upset when
|
||||
random data is sent to `/dev/ttyAMA0` when it is configured in bluetooth mode.
|
||||
To solve this, add `donotprobe=/dev/ttyAMA0`
|
||||
|
@ -125,9 +157,11 @@ bus the mbus poll request should be sent to.
|
|||
wmbusmeters --pollinterval=60s MAIN=/dev/ttyUSB0:mbus:2400 MyTempMeter piigth:MAIN:mbus 12001932 NOKEY
|
||||
```
|
||||
|
||||
If you want to poll an mbus meter using the primary address, just use
|
||||
a number between 0 and 250 instead of the full 8 digit secondary
|
||||
address.
|
||||
If you want to poll an mbus meter using the primary address, use p0 to p250 (deciman numbers)
|
||||
instead of the full 8 digit secondary address.
|
||||
```
|
||||
wmbusmeters --pollinterval=60s MAIN=/dev/ttyUSB0:mbus:2400 MyTempMeter piigth:MAIN:mbus p0 NOKEY
|
||||
```
|
||||
|
||||
# Example wmbusmeter.conf file
|
||||
|
||||
|
@ -168,7 +202,7 @@ And an mbus meter file in /etc/wmbusmeters.d/MyTempHygro
|
|||
```ini
|
||||
name=MyTempHygro
|
||||
id=11223344
|
||||
driver=piigth:mbus
|
||||
driver=piigth:MAIN:mbus
|
||||
pollinterval=60s
|
||||
```
|
||||
|
||||
|
@ -212,9 +246,15 @@ The latest reading of the meter can also be found here: `/var/lib/wmbusmeters/me
|
|||
You can use several ids using `id=1111111,2222222,3333333` or you can listen to all
|
||||
meters of a certain type `id=*` or you can suffix with star `id=8765*` to match
|
||||
all meters with a given prefix. If you supply at least one positive match rule, then you
|
||||
can add negative match rules as well. For example `id=*,!2222*`
|
||||
can add filter out rules as well. For example `id=*,!2222*`
|
||||
which will match all meter ids, except those that begin with 2222.
|
||||
|
||||
You can also specify the exact manufacturer, version and type: `id=11111111.M=KAM.V=1b.T=16`
|
||||
or a subset: `id=11111111.T=16` or all telegrams from 22222222 except those with version 77:
|
||||
`id=22222222,!22222222.V=77` You can also use the fully specified secondary address that is
|
||||
printed by libmbus after doing a bus scan, ie `100002842941011B` which is equivalent to
|
||||
`10000284.M=PII.V=01.T=1B`
|
||||
|
||||
When matching all meters from the command line you can use `ANYID` instead of `*` to avoid shell quotes.
|
||||
|
||||
# Add static and calculated fields to the output
|
||||
|
@ -390,7 +430,7 @@ depending on if you are running as a daemon or not.
|
|||
# Running without config files, good for experimentation and test.
|
||||
|
||||
```
|
||||
wmbusmeters version: 1.14.0
|
||||
wmbusmeters version: 1.15.0
|
||||
Usage: wmbusmeters {options} [device] { [meter_name] [meter_driver] [meter_id] [meter_key] }*
|
||||
wmbusmeters {options} [hex] { [meter_name] [meter_driver] [meter_id] [meter_key] }*
|
||||
wmbusmetersd {options} [pid_file]
|
||||
|
@ -409,9 +449,12 @@ As {options} you can use:
|
|||
--calculate_flow_f=flow_temperature_c
|
||||
--debug for a lot of information
|
||||
--donotprobe=<tty> do not auto-probe this tty. Use multiple times for several ttys or specify "all" for all ttys.
|
||||
--driver=<file> load a driver
|
||||
--driversdir=<dir> load all drivers in dir
|
||||
--exitafter=<time> exit program after time, eg 20h, 10m 5s
|
||||
--format=<hr/json/fields> for human readable, json or semicolon separated fields
|
||||
--help list all options
|
||||
--identitymode=(id|id-mfct|full|none) group meter state based on the identity mode. Default is id.
|
||||
--ignoreduplicates=<bool> ignore duplicate telegrams, remember the last 10 telegrams
|
||||
--field_xxx=yyy always add "xxx"="yyy" to the json output and add shell env METER_xxx=yyy (--json_xxx=yyy also works)
|
||||
--license print GPLv3+ license
|
||||
|
@ -430,6 +473,7 @@ As {options} you can use:
|
|||
--meterfilesnaming=(name|id|name-id) the meter file is the meter's: name, id or name-id
|
||||
--meterfilestimestamp=(never|day|hour|minute|micros) the meter file is suffixed with a
|
||||
timestamp (localtime) with the given resolution.
|
||||
--metershell=<cmdline> invokes cmdline with env variables the first time a meter is seen since startup
|
||||
--nodeviceexit if no wmbus devices are found, then exit immediately
|
||||
--normal for normal logging
|
||||
--oneshot wait for an update from each meter, then quit
|
||||
|
@ -473,10 +517,24 @@ These telegrams are expected to have the data link layer crc bytes removed alrea
|
|||
|
||||
`MAIN=/dev/ttyUSB0:mbus:2400`, assume ttyUSB0 is an serial to mbus-master converter. The speed is set to 2400 bps.
|
||||
|
||||
`rtlwmbus`, to spawn the background process: `rtl_sdr -f 868.625M -s 1600000 - 2>/dev/null | rtl_wmbus -s`
|
||||
`rtlwmbus`, to spawn the background process: `rtl_sdr -f 868.625M -s 1600000 - 2>/dev/null | rtl_wmbus -f -s`
|
||||
for each attached rtlsdr dongle. This will listen to S1,T1 and C1 meters in parallel.
|
||||
|
||||
Note that this uses a noticeable amount of CPU time by rtl_wmbus.
|
||||
For the moment, it is necessary to send the stderr to a file (/dev/null) because of a bug:
|
||||
https://github.com/osmocom/rtl-sdr/commit/142325a93c6ad70f851f43434acfdf75e12dfe03
|
||||
|
||||
Until this bug fix has propagated into Debian/Fedora etc, wmbusmeters uses a tmp file
|
||||
to see the stderr output from rtl_sdr. This tmp file is created in /tmp and will
|
||||
generate 420 bytes of data once ever 23 hours.
|
||||
|
||||
The current command line used by wmbusmeters to start the rtl_wmbus pipeline is therefore a bit longer:
|
||||
```
|
||||
ERRFILE=$(mktemp --suffix=_wmbusmeters_rtlsdr) ;
|
||||
echo ERRFILE=$ERRFILE ; date -Iseconds > $ERRFILE ;
|
||||
tail -f $ERRFILE & /usr/bin/rtl_sdr -d 0 -f 868.625M -s 1.6e6 - 2>>$ERRFILE | /usr/bin/rtl_wmbus -s -f
|
||||
```
|
||||
|
||||
Note that the standard -s option uses a noticeable amount of CPU time by rtl_wmbus.
|
||||
You can therefore use a tailored rtl_wmbus command that is more suitable for your needs.
|
||||
|
||||
`rtlwmbus:CMD(<command line>)`, to specify the entire background
|
||||
|
@ -486,9 +544,10 @@ The command line cannot contain parentheses.
|
|||
Likewise for rtl433.
|
||||
|
||||
Here is an example command line that reduces the rtl_wmbus CPU usage if you only need T1/C1 telegrams.
|
||||
It disable S1 decoding (`-p s`) and trades lower cpu usage for reception performance (`-a`):
|
||||
It disable S1 decoding (`-p s`) and trades lower cpu usage for reception performance (`-a`).
|
||||
You should always add the `-f` option to enable detection if rtl_sdr has stalled:
|
||||
|
||||
`rtlwmbus:CMD(rtl_sdr -f 868.95M -s 1600000 - 2>/dev/null | rtl_wmbus -p s -a)`
|
||||
`rtlwmbus:CMD(rtl_sdr -f 868.95M -s 1600000 - 2>/dev/null | rtl_wmbus -p s -a -f)`
|
||||
|
||||
`rtlwmbus(ppm=17)`, to tune your rtlsdr dongle accordingly.
|
||||
Use this to tune your dongle and at the same time listen to S1,T1 and C1.
|
||||
|
@ -791,12 +850,12 @@ wmbusmeters --format=json --meterfiles /dev/ttyUSB0:im871a:c1 MyTapWater multica
|
|||
# Using wmbusmeters in a pipe
|
||||
|
||||
```shell
|
||||
rtl_sdr -f 868.625M -s 1600000 - 2>/dev/null | rtl_wmbus -s | wmbusmeters --format=json stdin:rtlwmbus MyMeter auto 12345678 NOKEY | ...more processing...
|
||||
rtl_sdr -f 868.625M -s 1600000 - 2>/dev/null | rtl_wmbus -f -s | wmbusmeters --format=json stdin:rtlwmbus MyMeter auto 12345678 NOKEY | ...more processing...
|
||||
```
|
||||
|
||||
Or you can send rtl_wmbus formatted telegrams using nc over UDP to wmbusmeters.
|
||||
```shell
|
||||
rtl_sdr -f 868.95M -s 1600000 - 2>/dev/null | rtl_wmbus -p s -a | nc -u localhost 4444
|
||||
rtl_sdr -f 868.95M -s 1600000 - 2>/dev/null | rtl_wmbus -f -p s -a | nc -u localhost 4444
|
||||
```
|
||||
|
||||
And receive the telegrams with nc spawned by wmbusmeters.
|
||||
|
@ -809,6 +868,12 @@ Or start nc explicitly in a pipe.
|
|||
nc -lku 4444 | wmbusmeters stdin:rtlwmbus
|
||||
```
|
||||
|
||||
Telegrams can also be pulled in by listening on MQTT topics if they were captured by other tools like [rtl_433](https://github.com/merbanan/rtl_433)
|
||||
```shell
|
||||
wmbusmeters 'hex:CMD(/usr/bin/mosquitto_sub -h 192.168.x.x -t rtl_433/device/devices/6/Wireless-MBus/+/data | tr -d "\n" )'
|
||||
```
|
||||
`+` is a wild card that listens to all the captured telegrams but can be replaced with a specific meter's ID
|
||||
|
||||
# Decoding hex string telegrams
|
||||
|
||||
If you have a single telegram as hex, which you want decoded, you do not need to create a simulation file,
|
||||
|
|
|
@ -2969,6 +2969,53 @@ else $as_nop
|
|||
fi
|
||||
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for xmlFreeDoc in -lxml2" >&5
|
||||
printf %s "checking for xmlFreeDoc in -lxml2... " >&6; }
|
||||
if test ${ac_cv_lib_xml2_xmlFreeDoc+y}
|
||||
then :
|
||||
printf %s "(cached) " >&6
|
||||
else $as_nop
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lxml2 $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
namespace conftest {
|
||||
extern "C" int xmlFreeDoc ();
|
||||
}
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return conftest::xmlFreeDoc ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_cxx_try_link "$LINENO"
|
||||
then :
|
||||
ac_cv_lib_xml2_xmlFreeDoc=yes
|
||||
else $as_nop
|
||||
ac_cv_lib_xml2_xmlFreeDoc=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xml2_xmlFreeDoc" >&5
|
||||
printf "%s\n" "$ac_cv_lib_xml2_xmlFreeDoc" >&6; }
|
||||
if test "x$ac_cv_lib_xml2_xmlFreeDoc" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_LIBXML2 1" >>confdefs.h
|
||||
|
||||
LIBS="-lxml2 $LIBS"
|
||||
|
||||
else $as_nop
|
||||
|
||||
as_fn_error $? "Could not find libxml2 library. Try: sudo apt install libxml2-dev" "$LINENO" 5
|
||||
|
||||
fi
|
||||
|
||||
|
||||
ac_config_files="$ac_config_files $OUTPUT_ROOT/spec.gmk:$SRC_ROOT/autoconf/spec.gmk.in"
|
||||
|
||||
ac_config_files="$ac_config_files $OUTPUT_ROOT/Makefile:$SRC_ROOT/autoconf/Makefile.in"
|
||||
|
|
|
@ -53,6 +53,11 @@ AC_CHECK_LIB(rtlsdr, rtlsdr_get_device_count, [],
|
|||
AC_MSG_ERROR([Could not find rtlsdr library. Try: sudo apt install librtlsdr-dev])
|
||||
])
|
||||
|
||||
AC_CHECK_LIB(xml2, xmlFreeDoc, [],
|
||||
[
|
||||
AC_MSG_ERROR([Could not find libxml2 library. Try: sudo apt install libxml2-dev])
|
||||
])
|
||||
|
||||
AC_CONFIG_FILES([$OUTPUT_ROOT/spec.gmk:$SRC_ROOT/autoconf/spec.gmk.in])
|
||||
AC_CONFIG_FILES([$OUTPUT_ROOT/Makefile:$SRC_ROOT/autoconf/Makefile.in])
|
||||
|
||||
|
|
|
@ -35,11 +35,6 @@ Copyright: 2023 Fredrik Öhrström
|
|||
2021 Vincent Privat
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/driver_iperl.cc
|
||||
Copyright: 2022 Fredrik Öhrström
|
||||
2018 David Mallon
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/driver_izar.cc
|
||||
Copyright: 2019 Jacek Tomasiak
|
||||
2023 Fredrik Öhrström
|
||||
|
@ -54,7 +49,7 @@ License: GPL-3+
|
|||
|
||||
Files: src/driver_minomess.cc
|
||||
Copyright: 2021 Olli Salonen
|
||||
2022 Fredrik Öhrström
|
||||
2023 Fredrik Öhrström
|
||||
License: GPL-3+
|
||||
|
||||
Files: src/driver_sensostar.cc
|
||||
|
@ -106,6 +101,25 @@ License: GPL-3+
|
|||
On Debian systems, the complete text of the GNU General Public License
|
||||
version 3 can be found in file "/usr/share/common-licenses/GPL-3".
|
||||
|
||||
License: MIT
|
||||
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.
|
||||
|
||||
License: CC0
|
||||
The authors, and therefore would be copyright holders, have as much
|
||||
as possible relinguished their copyright to the public domain.
|
||||
|
|
|
@ -1,22 +1,41 @@
|
|||
FROM multiarch/alpine:${TARGETARCH}${TARGETVARIANT}-latest-stable AS build
|
||||
RUN apk add --no-cache alpine-sdk gcc linux-headers librtlsdr-dev cmake libusb-dev bash
|
||||
RUN git clone https://github.com/wmbusmeters/wmbusmeters.git && \
|
||||
FROM alpine AS build
|
||||
RUN apk add --no-cache alpine-sdk gcc linux-headers libxml2-dev cmake libusb-dev bash samurai
|
||||
|
||||
ADD https://api.github.com/repos/wmbusmeters/wmbusmeters/git/refs/heads/master version.json
|
||||
RUN git clone https://github.com/steve-m/librtlsdr.git && \
|
||||
git clone https://github.com/wmbusmeters/wmbusmeters.git && \
|
||||
git clone https://github.com/weetmuts/rtl-wmbus.git && \
|
||||
git clone https://github.com/merbanan/rtl_433.git
|
||||
git clone https://github.com/merbanan/rtl_433.git && \
|
||||
git clone https://github.com/ED6E0F17/rtl_reset.git
|
||||
WORKDIR /librtlsdr
|
||||
RUN cmake -B build -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=MinSizeRel \
|
||||
-DCMAKE_INSTALL_PREFIX:PATH=/usr \
|
||||
-DDETACH_KERNEL_DRIVER=ON \
|
||||
-Wno-dev && \
|
||||
cmake --build build && \
|
||||
cmake --install build
|
||||
WORKDIR /wmbusmeters
|
||||
RUN make
|
||||
WORKDIR /rtl-wmbus
|
||||
RUN make release && chmod 755 build/rtl_wmbus
|
||||
WORKDIR /rtl_433
|
||||
RUN mkdir build && cd build && cmake ../ && make
|
||||
RUN cmake -B build -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=MinSizeRel && \
|
||||
cmake --build build
|
||||
WORKDIR /rtl_reset
|
||||
RUN make
|
||||
|
||||
FROM multiarch/alpine:${TARGETARCH}${TARGETVARIANT}-latest-stable as scratch
|
||||
ENV QEMU_EXECVE=1
|
||||
RUN apk add --no-cache mosquitto-clients libstdc++ curl libusb rtl-sdr netcat-openbsd
|
||||
FROM alpine as scratch
|
||||
RUN apk add --no-cache mosquitto-clients libstdc++ curl libusb libxml2 netcat-openbsd
|
||||
WORKDIR /wmbusmeters
|
||||
COPY --from=build /librtlsdr/build/src/librtlsdr.so.* /usr/lib/
|
||||
COPY --from=build /librtlsdr/rtl-sdr.rules /usr/lib/udev/rules.d/rtl-sdr.rules
|
||||
COPY --from=build /librtlsdr/build/src/rtl_* /usr/bin/
|
||||
COPY --from=build /wmbusmeters/build/wmbusmeters /wmbusmeters/wmbusmeters
|
||||
COPY --from=build /rtl-wmbus/build/rtl_wmbus /usr/bin/rtl_wmbus
|
||||
COPY --from=build /rtl_433/build/src/rtl_433 /usr/bin/rtl_433
|
||||
COPY --from=build /rtl_reset/rtl_reset /usr/bin/rtl_reset
|
||||
COPY --from=build /wmbusmeters/docker/docker-entrypoint.sh /wmbusmeters/docker-entrypoint.sh
|
||||
VOLUME /wmbusmeters_data/
|
||||
CMD ["sh", "/wmbusmeters/docker-entrypoint.sh"]
|
||||
CMD ["sh", "/wmbusmeters/docker-entrypoint.sh"]
|
||||
|
|
|
@ -44,6 +44,9 @@ do
|
|||
elif grep -q -i "CC0" $f
|
||||
then
|
||||
license="CC0"
|
||||
elif grep -q -i "MIT" $f
|
||||
then
|
||||
license="MIT"
|
||||
else
|
||||
echo "Unknown license in file: "+$f
|
||||
exit 1
|
||||
|
@ -70,6 +73,25 @@ License: GPL-3+
|
|||
On Debian systems, the complete text of the GNU General Public License
|
||||
version 3 can be found in file "/usr/share/common-licenses/GPL-3".
|
||||
|
||||
License: MIT
|
||||
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.
|
||||
|
||||
License: CC0
|
||||
The authors, and therefore would be copyright holders, have as much
|
||||
as possible relinguished their copyright to the public domain.
|
||||
|
|
|
@ -13,7 +13,7 @@ then
|
|||
exit 1
|
||||
fi
|
||||
|
||||
(cd src; grep -Eo "Copyright \(C\) (....-)?.... [^\(]+ \(.+\)" * | cut -f 2 -d ':' | tr -s ' ' | sed 's/(C) \([0-9][0-9][0-9][0-9]\) /(C) \1-\1 /' > $TMP)
|
||||
(cd src; grep -Eo ".*Copyright \(C\) (....-)?.... [^\(]+ \(.+\)" * | cut -f 2 -d ':' | tr -s ' ' | sed 's/(C) \([0-9][0-9][0-9][0-9]\) /(C) \1-\1 /' > $TMP)
|
||||
|
||||
echo 'R"AUTHORS(' > $OUT
|
||||
|
||||
|
|
|
@ -50,3 +50,18 @@ then
|
|||
else
|
||||
echo "conf dir: $ROOT/etc/wmbusmeters.d unchanged"
|
||||
fi
|
||||
|
||||
####################################################################
|
||||
##
|
||||
## Create /etc/wmbusmeters.drivers.d
|
||||
##
|
||||
|
||||
if [ ! -d "$ROOT"/etc/wmbusmeters.drivers.d ]
|
||||
then
|
||||
# Create the drivers directory
|
||||
mkdir -p "$ROOT"/etc/wmbusmeters.drivers.d
|
||||
chmod -R 755 "$ROOT"/etc/wmbusmeters.drivers.d
|
||||
echo "conf dir: created $ROOT/etc/wmbusmeters.drivers.d"
|
||||
else
|
||||
echo "conf dir: $ROOT/etc/wmbusmeters.drivers.d unchanged"
|
||||
fi
|
||||
|
|
|
@ -44,6 +44,7 @@ then
|
|||
postrotate
|
||||
/bin/kill -HUP \`cat /run/wmbusmeters/wmbusmeters.pid 2> /dev/null\` 2> /dev/null || true
|
||||
endscript
|
||||
}
|
||||
EOF
|
||||
echo "logrotate: created $ROOT/etc/logrotate.d/wmbusmeters"
|
||||
else
|
||||
|
|
|
@ -55,4 +55,4 @@ telegram=|494468509494949495377286868686A85CFE07A90030052F2F_0413100000000F52FCF
|
|||
|
||||
# Test Zenner Minomess C1 water meter
|
||||
telegram=|6644496A1064035514377251345015496A0007EE0050052F2F_0C1359000000026CBE2B82046CA12B8C0413FFFFFFFF8D0493132CFBFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02FD1700002F2F|
|
||||
{"media":"water","meter":"minomess","name":"Mino","id":"15503451","meter_date":"2021-11-30","total_m3":0.059,"target_m3":244444.442,"target_date":"2021-11-01","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
{"media":"water","meter":"minomess","name":"Mino","id":"15503451","meter_date":"2021-11-30","total_m3":0.059,"target_date":"2021-11-01","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
telegram=|7B4479169977997730378C208B900F002C25E4EF0A002EA98E7D58B3ADC57299779977991611028B005087102F2F#0DFD090F34302e3030562030303030303030300D790E31323334353637383839595345310DFD100AAAAAAAAAAAAAAAAAAAAA0D780E31323334353637383930594553312F2F2F2F2F2F2F2F2F2F2F|
|
||||
telegram=|7B4479169977997730378C20F0900F002C2549EE0A0077C19D3D1A08ABCD729977997779161102F0005007102F2F#0702F5C3FA000000000007823C5407000000000000841004E081020084200415000000042938AB000004A9FF01FA0A000004A9FF02050A000004A9FF03389600002F2F2F2F2F2F2F2F2F2F2F2F2F|
|
|
@ -0,0 +1,19 @@
|
|||
telegram=|A244EE4D785634123C067A8F000000_0C1348550000426CE1F14C130000000082046C21298C0413330000008D04931E3A3CFE3300000033000000330000003300000033000000330000003300000033000000330000003300000033000000330000004300000034180000046D0D0B5C2B03FD6C5E150082206C5C290BFD0F0200018C4079678885238310FD3100000082106C01018110FD610002FD66020002FD170000|
|
||||
{"media":"warm water","meter":"supercom587","name":"MyWarmWater","id":"12345678","total_m3":5.548,"software_version":"010002","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
|MyWarmWater;12345678;5.548;1111-11-11 11:11.11
|
||||
|
||||
telegram=|A244EE4D111111113C077AAC000000_0C1389490000426CE1F14C130000000082046C21298C0413010000008D04931E3A3CFE0100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000001600000031130000046D0A0C5C2B03FD6C60150082206C5C290BFD0F0200018C4079629885238310FD3100000082106C01018110FD610002FD66020002FD170000|
|
||||
{"media":"water","meter":"supercom587","name":"MyColdWater","id":"11111111","total_m3":4.989,"software_version":"010002","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
|MyColdWater;11111111;4.989;1111-11-11 11:11.11
|
||||
|
||||
telegram=|1E44AE4C9956341268077A36001000_2F2F0413181E0000023B00002F2F2F2F|
|
||||
{"media":"water","meter":"iperl","name":"MoreWater","id":"12345699","total_m3":7.704,"max_flow_m3h":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|MoreWater;12345699;7.704;0;1111-11-11 11:11.11
|
||||
|
||||
telegram=|1844AE4C4455223368077A55000000_041389E20100023B0000|
|
||||
{"media":"water","meter":"iperl","name":"WaterWater","id":"33225544","total_m3":123.529,"max_flow_m3h":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|WaterWater;33225544;123.529;0;1111-11-11 11:11.11
|
||||
|
||||
telegram=|31446850226677116980A0119F27020480048300C408F709143C003D341A2B0B2A0707000000000000062D114457563D71A1850000|
|
||||
{"media":"heat cost allocator","meter":"fhkvdataiii","name":"Room","id":"11776622","current_hca":131,"current_date":"2020-02-08T02:00:00Z","previous_hca":1026,"previous_date":"2019-12-31T02:00:00Z","temp_room_c":22.44,"temp_radiator_c":25.51,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|Room;11776622;131;2020-02-08T02:00:00Z;1026;2019-12-31T02:00:00Z;22.44;25.51;1111-11-11 11:11.11
|
|
@ -0,0 +1,4 @@
|
|||
telegram=|A244EE4D785634123C067A8F000000|0C1348550000426CE1F14C130000000082046C21298C0413330000008D04931E3A3CFE3300000033000000330000003300000033000000330000003300000033000000330000003300000033000000330000004300000034180000046D0D0B5C2B03FD6C5E150082206C5C290BFD0F0200018C4079678885238310FD3100000082106C01018110FD610002FD66020002FD170000|
|
||||
{"media":"warm water","meter":"supercom587","name":"MyWarmWater","id":"12345678","total_m3":5.548,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
telegram=|A244EE4D785634123C067A8F000000|0C1348560000426CE1F14C130000000082046C21298C0413330000008D04931E3A3CFE3300000033000000330000003300000033000000330000003300000033000000330000003300000033000000330000004300000034180000046D0D0B5C2B03FD6C5E150082206C5C290BFD0F0200018C4079678885238310FD3100000082106C01018110FD610002FD66020002FD170000|
|
||||
{"media":"warm water","meter":"supercom587","name":"MyWarmWater","id":"12345678","total_m3":6.548,"timestamp":"1111-11-11T11:11:11Z"}
|
|
@ -0,0 +1,4 @@
|
|||
telegram=|414493447514916746377275149167934446044D000020_0C06490000004C0600000000426CFF2CCC080611000000C2086C1F3102FD170000326CFFFF046D330F1432|
|
||||
telegram=|5b44934475149167463778077975149167934446040dff5f3500823d0000810007c006ffff49000000ff2c000000001f3111000000008000800080008000800080008000800080000000000B002f02fd170000046d390d1432488408|
|
||||
telegram=|414493447514916746377275149167934446044D000020_0C06490000004C0600000000426CFF2CCC080611000000C2086C1F3102FD170000326CFFFF046D330F1432|
|
||||
telegram=|5b44934475149167463778077975149167934446040dff5f3500823d0000810007c006ffff49000000ff2c000000001f3111000000008000800080008000800080008000800080000000000B002f02fd170000046d390d1432488408|
|
|
@ -43,8 +43,8 @@ telegram=|5E44B6105843250000027A2A005005_2F2F0C7835221400066D404708AC2A400E03202
|
|||
# There is a problem in the decoding here, the data stored inside the telegram does not seem to properly encode/decode the year....
|
||||
# We should not report a current_date with a full year, if the year is actually not part of the telegram.
|
||||
telegram=|2F446850313233347462A2_069F255900B029310000000306060906030609070606050509050505050407040605070500|
|
||||
{"media":"warm water","meter":"mkradio3","name":"Duschen","id":"34333231","total_m3":13.8,"target_m3":8.9,"current_date":"2023-04-27T02:00:00Z","prev_date":"2018-12-31T02:00:00Z","timestamp":"1111-11-11T11:11:11Z"}
|
||||
|Duschen;34333231;13.8;8.9;2023-04-27T02:00:00Z;2018-12-31T02:00:00Z;1111-11-11 11:11.11
|
||||
{"media":"warm water","meter":"mkradio3","name":"Duschen","id":"34333231","total_m3":13.8,"target_m3":8.9,"current_date":"2024-04-27T02:00:00Z","prev_date":"2018-12-31T02:00:00Z","timestamp":"1111-11-11T11:11:11Z"}
|
||||
|Duschen;34333231;13.8;8.9;2024-04-27T02:00:00Z;2018-12-31T02:00:00Z;1111-11-11 11:11.11
|
||||
|
||||
# Test MKRadio4 T1 telegrams
|
||||
|
||||
|
@ -60,7 +60,7 @@ telegram=|374468506549235827C3A2_129F25383300A8622600008200800A2AF86211517555287
|
|||
# Test FHKV data II/III
|
||||
# There is a problem in the decoding here, the data stored inside the telegram does not seem to properly encode/decode the year....
|
||||
# We should not report a current_date with a full year, if the year is actually not part of the telegram.
|
||||
telegram=|31446850226677116980A0119F27020480048300C408F709143C003D341A2B0B2A0707000000000000062D114457563D71A1850000|
|
||||
telegram=|34446850226677116980A0119F27020480048300C408F709143C003D341A2B0B2A0707000000000000062D114457563D71A1850000|
|
||||
{"media":"heat cost allocator","meter":"fhkvdataiii","name":"Room","id":"11776622","current_hca":131,"current_date":"2020-02-08T02:00:00Z","previous_hca":1026,"previous_date":"2019-12-31T02:00:00Z","temp_room_c":22.44,"temp_radiator_c":25.51,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|Room;11776622;131;2020-02-08T02:00:00Z;1026;2019-12-31T02:00:00Z;22.44;25.51;1111-11-11 11:11.11
|
||||
|
||||
|
@ -122,13 +122,13 @@ telegram=|5744b40988227711101b7ab20800000265a00842658f088201659f08226589081265a0
|
|||
|
||||
# Test Hydrus water meter telegram
|
||||
telegram=|4E44A5116464646470077AED004005_2F2F01FD08300C13741100007C1300000000FC101300000000FC201300000000726C00000B3B00000002FD748713025A6800C4016D3B177F2ACC011300020000|
|
||||
{"at_datetime": "2019-10-31 23:59","flow_m3h": 0,"flow_temperature_c": 10.4,"id": "64646464","media": "water","meter": "hydrus","name": "HydrusWater","remaining_battery_life_y": 13.686797,"status": "OK","timestamp": "1111-11-11T11:11:11Z","total_at_date_m3": 0.2,"total_m3": 1.174}
|
||||
|HydrusWater;64646464;1.174;0.2;OK;1111-11-11 11:11.11
|
||||
{"target_datetime": "2019-10-31 23:59","flow_m3h": 0,"flow_temperature_c": 10.4,"id": "64646464","media": "water","meter": "hydrus","name": "HydrusWater","remaining_battery_life_y": 13.686797,"status": "OK","timestamp": "1111-11-11T11:11:11Z","target_m3": 0.2,"total_m3": 1.174}
|
||||
|HydrusWater;64646464;1.174;null;OK;1111-11-11 11:11.11
|
||||
|
||||
# Test Hydrus new version water meter telegram
|
||||
telegram=|3E44A5116565656570067AFB0030052F2F_0C13503400000DFD110A383731303134423032410B3B00000002FD74DC15C4016D3B178D29CC0113313400002F2F|
|
||||
{"at_datetime": "2020-09-13 23:59","customer": "A20B410178","flow_m3h": 0,"id": "65656565","media": "warm water","meter": "hydrus","name": "HydrusVater","remaining_battery_life_y": 15.321328,"status": "OK","timestamp": "1111-11-11T11:11:11Z","total_at_date_m3": 3.431,"total_m3": 3.45}
|
||||
|HydrusVater;65656565;3.45;3.431;OK;1111-11-11 11:11.11
|
||||
{"target_datetime": "2020-09-13 23:59","customer": "A20B410178","flow_m3h": 0,"id": "65656565","media": "warm water","meter": "hydrus","name": "HydrusVater","remaining_battery_life_y": 15.321328,"status": "OK","timestamp": "1111-11-11T11:11:11Z","target_m3": 3.431,"total_m3": 3.45}
|
||||
|HydrusVater;65656565;3.45;null;OK;1111-11-11 11:11.11
|
||||
|
||||
# Test Hydrus with default AES encryption
|
||||
telegram=||6644242328001081640E7266567464A51170071F0050052C411A08674048DD6BA82A0DF79FFD401309179A893A1BE3CE8EDC50C2A45CD7AFEC3B4CE765820BE8056C124A17416C3722985FFFF7FCEB7094901AB3A16294B511B9A740C9F9911352B42A72FB3B0C|
|
||||
|
@ -152,7 +152,7 @@ telegram=|2E4409077272727210077AD71020052F2F_046D040D742C041377000000446D0000612
|
|||
|
||||
# Test Axioma W1 telegram with additional fields compared to the older q400 meter.
|
||||
telegram=|5E4409077372727210077A710050052F2F_046D0110A92704130000000004933B0000000004933C00000000023B000002592A0A446D0000A12744130000000044933B0000000044933C0000000001FD74622F2F2F2F2F2F2F2F2F2F2F2F2F2F|
|
||||
{"media":"water","meter":"q400","name":"AxiomaWater","id":"72727273","meter_datetime":"2021-07-09 16:01","total_m3":0,"total_forward_m3":0,"total_backward_m3":0,"flow_temperature_c":26.02,"volume_flow_m3h":0,"status":"OK","set_datetime":"2021-07-01 00:00","consumption_at_set_date_m3":0,"forward_at_set_date_m3":0,"backward_at_set_date_m3":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
{"media":"water","meter":"q400","name":"AxiomaWater","id":"72727273","meter_datetime":"2021-07-09 16:01","total_m3":0,"total_forward_m3":0,"total_backward_m3":0,"flow_temperature_c":26.02,"volume_flow_m3h":0,"status":"OK","set_datetime":"2021-07-01 00:00","consumption_at_set_date_m3":0,"forward_at_set_date_m3":0,"backward_at_set_date_m3":0,"battery_pct":98,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|AxiomaWater;72727273;0;1111-11-11 11:11.11
|
||||
|
||||
# Test electricity meter with eBZ wMB E01.
|
||||
|
@ -199,7 +199,7 @@ telegram=|3944FA122162092002067A3600202567C94D48D00DC47B11213E23383DB51968A705AA
|
|||
# Test topaseskr water meter
|
||||
|
||||
telegram=|4E44B40512345678F1077A310040052F2F_01FD08040C13991848004C1359423500CC101300000000CC201359423500426C7F2C0B3B00000002FD74DA10025AD300C4016D3B179F27CC011387124600|
|
||||
{"media":"water","meter":"topaseskr","name":"Witer","id":"78563412","total_m3":481.899,"access_counter":4,"temperature_c":21.1,"current_flow_m3h":0,"volume_year_period_m3":354.259,"reverse_volume_year_period_m3":0,"meter_year_period_start_date":"2019-12-31","volume_month_period_m3":461.287,"meter_month_period_start_datetime":"2020-07-31 23:59","battery_y":11.811331,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
{"media":"water","meter":"topaseskr","name":"Witer","id":"78563412","total_m3":481.899,"access_counter":4,"temperature_c":21.1,"current_flow_m3h":0,"volume_year_period_m3":354.259,"reverse_volume_year_period_m3":0,"meter_year_period_end_date":"2019-12-31","volume_month_period_m3":461.287,"meter_month_period_end_datetime":"2020-07-31 23:59","battery_y":11.811331,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|Witer;78563412;481.899;21.1;0;354.259;0;2019-12-31;461.287;2020-07-31 23:59;1111-11-11 11:11.11
|
||||
|
||||
# Test Ultrimis water meter
|
||||
|
|
|
@ -49,6 +49,8 @@ parts:
|
|||
- g++
|
||||
- make
|
||||
- librtlsdr-dev
|
||||
- libxml2-dev
|
||||
- libxslt1-dev
|
||||
stage-packages:
|
||||
- mosquitto-clients
|
||||
- curl
|
||||
|
@ -56,6 +58,7 @@ parts:
|
|||
- sysvinit-utils
|
||||
- libusb-1.0-0
|
||||
- rtl-sdr
|
||||
- libxml2
|
||||
prime:
|
||||
- sbin/
|
||||
- usr/bin/
|
||||
|
|
|
@ -0,0 +1,656 @@
|
|||
/*
|
||||
Copyright (C) 2017-2024 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include"address.h"
|
||||
#include"manufacturers.h"
|
||||
|
||||
#include<assert.h>
|
||||
#include<algorithm>
|
||||
#include<string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
vector<string> splitSequenceOfAddressExpressionsAtCommas(const string& mes);
|
||||
bool isValidMatchExpression(const std::string& s, bool *has_wildcard);
|
||||
bool doesIdMatchExpression(const std::string& id, std::string match_rule);
|
||||
bool doesAddressMatchExpressions(Address &address,
|
||||
std::vector<AddressExpression>& address_expressions,
|
||||
bool *used_wildcard,
|
||||
bool *filtered_out,
|
||||
bool *required_found,
|
||||
bool *required_failed);
|
||||
|
||||
bool isValidMatchExpression(const string& s, bool *has_wildcard)
|
||||
{
|
||||
string me = s;
|
||||
|
||||
// Examples of valid match expressions:
|
||||
// 12345678
|
||||
// *
|
||||
// 123*
|
||||
// !12345677
|
||||
// 2222222*
|
||||
// !22222222
|
||||
// We also accept an secondary libmbus address:
|
||||
// 100002842941011B
|
||||
|
||||
// A match expression cannot be empty.
|
||||
if (me.length() == 0) return false;
|
||||
|
||||
// An me can be filtered out with an exclamation mark first.
|
||||
if (me.front() == '!') me.erase(0, 1);
|
||||
|
||||
// More than one negation is not allowed.
|
||||
if (me.front() == '!') return false;
|
||||
|
||||
// A match expression cannot be only a negation mark.
|
||||
if (me.length() == 0) return false;
|
||||
|
||||
int count = 0;
|
||||
// Some non-compliant meters have full hex in the id,
|
||||
// but according to the standard there should only be bcd here...
|
||||
// We accept hex anyway.
|
||||
while (me.length() > 0 &&
|
||||
((me.front() >= '0' && me.front() <= '9') ||
|
||||
(me.front() >= 'A' && me.front() <= 'F') ||
|
||||
(me.front() >= 'a' && me.front() <= 'f')))
|
||||
{
|
||||
me.erase(0,1);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (me.length() == 0 && count == 16)
|
||||
{
|
||||
// A secondary libmbus address: 100002842941011B
|
||||
// Strictly speaking the leading 8 digits should be bcd,
|
||||
// but we accept hex as well.
|
||||
*has_wildcard = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wildcard_used = false;
|
||||
// An expression can end with a *
|
||||
if (me.length() > 0 && me.front() == '*')
|
||||
{
|
||||
me.erase(0,1);
|
||||
wildcard_used = true;
|
||||
if (has_wildcard) *has_wildcard = true;
|
||||
}
|
||||
|
||||
// Now we should have eaten the whole expression.
|
||||
if (me.length() > 0) return false;
|
||||
|
||||
// Check the length of the matching bcd/hex
|
||||
// If no wildcard is used, then the match expression must be exactly 8 digits.
|
||||
if (!wildcard_used) return count == 8;
|
||||
|
||||
// If wildcard is used, then the match expressions must be 7 or less digits,
|
||||
// even zero is allowed which means a single *, which matches any bcd/hex id.
|
||||
return count <= 7;
|
||||
}
|
||||
|
||||
vector<string> splitSequenceOfAddressExpressionsAtCommas(const string& mes)
|
||||
{
|
||||
vector<string> r;
|
||||
bool eof, err;
|
||||
vector<uchar> v (mes.begin(), mes.end());
|
||||
auto i = v.begin();
|
||||
|
||||
for (;;) {
|
||||
auto id = eatTo(v, i, ',', 64, &eof, &err);
|
||||
if (err) break;
|
||||
trimWhitespace(&id);
|
||||
if (id == "ANYID") id = "*";
|
||||
r.push_back(id);
|
||||
if (eof) break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool isValidSequenceOfAddressExpressions(const string& mes)
|
||||
{
|
||||
vector<string> v = splitSequenceOfAddressExpressionsAtCommas(mes);
|
||||
|
||||
for (string me : v)
|
||||
{
|
||||
AddressExpression ae;
|
||||
if (!ae.parse(me)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<AddressExpression> splitAddressExpressions(const string &aes)
|
||||
{
|
||||
vector<string> v = splitSequenceOfAddressExpressionsAtCommas(aes);
|
||||
|
||||
vector<AddressExpression> r;
|
||||
|
||||
for (string me : v)
|
||||
{
|
||||
AddressExpression ae;
|
||||
if (ae.parse(me))
|
||||
{
|
||||
r.push_back(ae);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool doesIdMatchExpression(const string& s, string match)
|
||||
{
|
||||
string id = s;
|
||||
if (id.length() == 0) return false;
|
||||
|
||||
// Here we assume that the match expression has been
|
||||
// verified to be valid.
|
||||
bool can_match = true;
|
||||
|
||||
// Now match bcd/hex until end of id, or '*' in match.
|
||||
while (id.length() > 0 && match.length() > 0 && match.front() != '*')
|
||||
{
|
||||
if (id.front() != match.front())
|
||||
{
|
||||
// We hit a difference, it cannot match.
|
||||
can_match = false;
|
||||
break;
|
||||
}
|
||||
id.erase(0,1);
|
||||
match.erase(0,1);
|
||||
}
|
||||
|
||||
bool wildcard_used = false;
|
||||
if (match.length() && match.front() == '*')
|
||||
{
|
||||
wildcard_used = true;
|
||||
match.erase(0,1);
|
||||
}
|
||||
|
||||
if (can_match)
|
||||
{
|
||||
// Ok, now the match expression should be empty.
|
||||
// If wildcard is true, then the id can still have digits,
|
||||
// otherwise it must also be empty.
|
||||
if (wildcard_used)
|
||||
{
|
||||
can_match = match.length() == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
can_match = match.length() == 0 && id.length() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
return can_match;
|
||||
}
|
||||
|
||||
bool hasWildCard(const string& mes)
|
||||
{
|
||||
return mes.find('*') != string::npos;
|
||||
}
|
||||
|
||||
bool AddressExpression::match(const std::string &i, uint16_t m, uchar v, uchar t)
|
||||
{
|
||||
if (!(mfct == 0xffff || mfct == m)) return false;
|
||||
if (!(version == 0xff || version == v)) return false;
|
||||
if (!(type == 0xff || type == t)) return false;
|
||||
if (!doesIdMatchExpression(i, id)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddressExpression::trimToIdentity(IdentityMode im, Address &a)
|
||||
{
|
||||
switch (im)
|
||||
{
|
||||
case IdentityMode::FULL:
|
||||
id = a.id;
|
||||
mfct = a.mfct;
|
||||
version = a.version;
|
||||
type = a.type;
|
||||
required = true;
|
||||
break;
|
||||
case IdentityMode::ID_MFCT:
|
||||
id = a.id;
|
||||
mfct = a.mfct;
|
||||
version = 0xff;
|
||||
type = 0xff;
|
||||
required = true;
|
||||
break;
|
||||
case IdentityMode::ID:
|
||||
id = a.id;
|
||||
mfct = 0xffff;
|
||||
version = 0xff;
|
||||
type = 0xff;
|
||||
required = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool AddressExpression::parse(const string &in)
|
||||
{
|
||||
string s = in;
|
||||
// Example: 12345678
|
||||
// or 12345678.M=PII.T=1B.V=01
|
||||
// or 1234*
|
||||
// or 1234*.M=PII
|
||||
// or 1234*.V=01
|
||||
// or 12 // mbus primary
|
||||
// or 0 // mbus primary
|
||||
// or 250.MPII.V01.T1B // mbus primary
|
||||
// or !12345678
|
||||
// or !*.M=ABC
|
||||
// or libmbus secondary style:
|
||||
// 123456782941011B
|
||||
id = "";
|
||||
mbus_primary = false;
|
||||
mfct = 0xffff;
|
||||
type = 0xff;
|
||||
version = 0xff;
|
||||
filter_out = false;
|
||||
|
||||
if (s.size() == 0) return false;
|
||||
|
||||
if (s.size() > 1 && s[0] == '!')
|
||||
{
|
||||
filter_out = true;
|
||||
s = s.substr(1);
|
||||
// Double ! not allowed.
|
||||
if (s.size() > 1 && s[0] == '!') return false;
|
||||
}
|
||||
vector<string> parts = splitString(s, '.');
|
||||
|
||||
assert(parts.size() > 0);
|
||||
|
||||
id = parts[0];
|
||||
if (!isValidMatchExpression(id, &has_wildcard))
|
||||
{
|
||||
// Not a long id, so lets check if it is p0 to p250 for primary mbus ids.
|
||||
if (id.size() < 2) return false;
|
||||
if (id[0] != 'p') return false;
|
||||
for (size_t i=1; i < id.length(); ++i)
|
||||
{
|
||||
if (!isdigit(id[i])) return false;
|
||||
}
|
||||
// All digits good.
|
||||
int v = atoi(id.c_str()+1);
|
||||
if (v < 0 || v > 250) return false;
|
||||
// It is 0-250 which means it is an mbus primary address.
|
||||
mbus_primary = true;
|
||||
}
|
||||
|
||||
if (parts.size() == 1 && id.length() == 16)
|
||||
{
|
||||
// This is a secondary libmbus address.
|
||||
string mfct_hex = id.substr(8,4);
|
||||
string version_hex = id.substr(12,2);
|
||||
string type_hex = id.substr(14,2);
|
||||
id = id.substr(0,8);
|
||||
|
||||
vector<uchar> data;
|
||||
bool ok = hex2bin(mfct_hex.c_str(), &data);
|
||||
if (!ok) return false;
|
||||
if (data.size() != 2) return false;
|
||||
mfct = data[1] << 8 | data[0];
|
||||
|
||||
data.clear();
|
||||
ok = hex2bin(version_hex.c_str(), &data);
|
||||
if (!ok) return false;
|
||||
if (data.size() != 1) return false;
|
||||
version = data[0];
|
||||
|
||||
data.clear();
|
||||
ok = hex2bin(type_hex.c_str(), &data);
|
||||
if (!ok) return false;
|
||||
if (data.size() != 1) return false;
|
||||
type = data[0];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
for (size_t i=1; i<parts.size(); ++i)
|
||||
{
|
||||
if (parts[i].size() == 4) // V=xy or T=xy
|
||||
{
|
||||
if (parts[i][1] != '=') return false;
|
||||
|
||||
vector<uchar> data;
|
||||
bool ok = hex2bin(&parts[i][2], &data);
|
||||
if (!ok) return false;
|
||||
if (data.size() != 1) return false;
|
||||
|
||||
if (parts[i][0] == 'V')
|
||||
{
|
||||
version = data[0];
|
||||
}
|
||||
else if (parts[i][0] == 'T')
|
||||
{
|
||||
type = data[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (parts[i].size() == 5) // M=xyz
|
||||
{
|
||||
if (parts[i][1] != '=') return false;
|
||||
if (parts[i][0] != 'M') return false;
|
||||
|
||||
bool ok = flagToManufacturer(&parts[i][2], &mfct);
|
||||
if (!ok) return false;
|
||||
}
|
||||
else if (parts[i].size() == 6) // M=abcd explicit hex version
|
||||
{
|
||||
if (parts[i][1] != '=') return false;
|
||||
if (parts[i][0] != 'M') return false;
|
||||
|
||||
vector<uchar> data;
|
||||
bool ok = hex2bin(&parts[i][2], &data);
|
||||
if (!ok) return false;
|
||||
if (data.size() != 2) return false;
|
||||
|
||||
mfct = data[1] << 8 | data[0];
|
||||
if (!ok) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool flagToManufacturer(const char *s, uint16_t *out_mfct)
|
||||
{
|
||||
if (s[0] == 0 || s[1] == 0 || s[2] == 0 || s[3] != 0) return false;
|
||||
if (s[0] < '@' || s[0] > 'Z' ||
|
||||
s[1] < '@' || s[1] > 'Z' ||
|
||||
s[2] < '@' || s[2] > 'Z') return false;
|
||||
|
||||
*out_mfct = MANFCODE(s[0],s[1],s[2]);
|
||||
return true;
|
||||
}
|
||||
|
||||
string AddressExpression::str()
|
||||
{
|
||||
string s;
|
||||
|
||||
if (filter_out) s = "!";
|
||||
if (required) s = "R";
|
||||
|
||||
s.append(id);
|
||||
if (mfct != 0xffff)
|
||||
{
|
||||
s += ".M="+manufacturerFlag(mfct);
|
||||
}
|
||||
if (version != 0xff)
|
||||
{
|
||||
s += ".V="+tostrprintf("%02x", version);
|
||||
}
|
||||
if (type != 0xff)
|
||||
{
|
||||
s += ".T="+tostrprintf("%02x", type);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
string Address::str()
|
||||
{
|
||||
string s;
|
||||
|
||||
s.append(id);
|
||||
if (mfct != 0xffff)
|
||||
{
|
||||
s += ".M="+manufacturerFlag(mfct);
|
||||
}
|
||||
if (version != 0xff)
|
||||
{
|
||||
s += ".V="+tostrprintf("%02x", version);
|
||||
}
|
||||
if (type != 0xff)
|
||||
{
|
||||
s += ".T="+tostrprintf("%02x", type);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
string Address::concat(std::vector<Address> &addresses)
|
||||
{
|
||||
string s;
|
||||
for (Address& a: addresses)
|
||||
{
|
||||
if (s.size() > 0) s.append(",");
|
||||
s.append(a.str());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
string AddressExpression::concat(std::vector<AddressExpression> &address_expressions)
|
||||
{
|
||||
string s;
|
||||
for (AddressExpression& a: address_expressions)
|
||||
{
|
||||
if (s.size() > 0) s.append(",");
|
||||
s.append(a.str());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
string manufacturerFlag(int m_field) {
|
||||
char a = (m_field/1024)%32+64;
|
||||
char b = (m_field/32)%32+64;
|
||||
char c = (m_field)%32+64;
|
||||
|
||||
string flag;
|
||||
flag += a;
|
||||
flag += b;
|
||||
flag += c;
|
||||
return flag;
|
||||
}
|
||||
|
||||
void Address::decodeMfctFirst(const vector<uchar>::iterator &pos)
|
||||
{
|
||||
mfct = *(pos+1) << 8 | *(pos+0);
|
||||
id = tostrprintf("%02x%02x%02x%02x", *(pos+5), *(pos+4), *(pos+3), *(pos+2));
|
||||
version = *(pos+6);
|
||||
type = *(pos+7);
|
||||
}
|
||||
|
||||
void Address::decodeIdFirst(const vector<uchar>::iterator &pos)
|
||||
{
|
||||
id = tostrprintf("%02x%02x%02x%02x", *(pos+3), *(pos+2), *(pos+1), *(pos+0));
|
||||
mfct = *(pos+5) << 8 | *(pos+4);
|
||||
version = *(pos+6);
|
||||
type = *(pos+7);
|
||||
}
|
||||
|
||||
bool doesTelegramMatchExpressions(std::vector<Address> &addresses,
|
||||
std::vector<AddressExpression>& address_expressions,
|
||||
bool *used_wildcard)
|
||||
{
|
||||
bool match = false;
|
||||
bool filtered_out = false;
|
||||
bool required_found = false; // An R12345678 field was found.
|
||||
bool required_failed = true; // Init to fail, set to true if R is satistifed anywhere.
|
||||
|
||||
for (Address &a : addresses)
|
||||
{
|
||||
if (doesAddressMatchExpressions(a,
|
||||
address_expressions,
|
||||
used_wildcard,
|
||||
&filtered_out,
|
||||
&required_found,
|
||||
&required_failed))
|
||||
{
|
||||
match = true;
|
||||
}
|
||||
// Go through all ids even though there is an early match.
|
||||
// This way we can see if theres an exact match later.
|
||||
}
|
||||
// If any expression triggered a filter out, then the whole telegram does not match.
|
||||
if (filtered_out) match = false;
|
||||
// If a required field was found and it failed....
|
||||
if (required_found && required_failed) match = false;
|
||||
return match;
|
||||
}
|
||||
|
||||
bool doesAddressMatchExpressions(Address &address,
|
||||
vector<AddressExpression>& address_expressions,
|
||||
bool *used_wildcard,
|
||||
bool *filtered_out,
|
||||
bool *required_found,
|
||||
bool *required_failed)
|
||||
{
|
||||
bool found_match = false;
|
||||
bool found_negative_match = false;
|
||||
bool exact_match = false;
|
||||
|
||||
// Goes through all possible match expressions.
|
||||
// If no expression matches, neither positive nor negative,
|
||||
// then the result is false. (ie no match)
|
||||
|
||||
// If more than one positive match is found, and no negative,
|
||||
// then the result is true.
|
||||
|
||||
// If more than one negative match is found, irrespective
|
||||
// if there is any positive matches or not, then the result is false.
|
||||
|
||||
// If a positive match is found, using a wildcard not any exact match,
|
||||
// then *used_wildcard is set to true.
|
||||
|
||||
// If an expression is required and it fails, then the match fails.
|
||||
for (AddressExpression &ae : address_expressions)
|
||||
{
|
||||
bool has_wildcard = ae.has_wildcard;
|
||||
bool is_negative_rule = ae.filter_out;
|
||||
// We currently assume that only a single expression is required, the last one!
|
||||
bool is_required = ae.required;
|
||||
|
||||
if (is_required) *required_found = true;
|
||||
|
||||
bool m = ae.match(address.id, address.mfct, address.version, address.type);
|
||||
|
||||
if (is_negative_rule)
|
||||
{
|
||||
if (m) found_negative_match = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m)
|
||||
{
|
||||
// A match, but the required does not count.
|
||||
if (!is_required)
|
||||
{
|
||||
found_match = true;
|
||||
if (!has_wildcard)
|
||||
{
|
||||
exact_match = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*required_failed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found_negative_match)
|
||||
{
|
||||
*filtered_out = true;
|
||||
return false;
|
||||
}
|
||||
if (found_match)
|
||||
{
|
||||
if (exact_match)
|
||||
{
|
||||
*used_wildcard = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*used_wildcard = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *toString(IdentityMode im)
|
||||
{
|
||||
switch (im)
|
||||
{
|
||||
case IdentityMode::ID: return "id";
|
||||
case IdentityMode::ID_MFCT: return "id-mfct";
|
||||
case IdentityMode::FULL: return "full";
|
||||
case IdentityMode::NONE: return "none";
|
||||
case IdentityMode::INVALID: return "invalid";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
IdentityMode toIdentityMode(const char *s)
|
||||
{
|
||||
if (!strcmp(s,"id")) return IdentityMode::ID;
|
||||
if (!strcmp(s,"id-mfct")) return IdentityMode::ID_MFCT;
|
||||
if (!strcmp(s, "full")) return IdentityMode::FULL;
|
||||
if (!strcmp(s, "none")) return IdentityMode::NONE;
|
||||
return IdentityMode::INVALID;
|
||||
}
|
||||
|
||||
void AddressExpression::clear()
|
||||
{
|
||||
id = "";
|
||||
has_wildcard = false;
|
||||
mbus_primary = false;
|
||||
mfct = 0xffff;
|
||||
version = 0xff;
|
||||
type = 0xff;
|
||||
}
|
||||
|
||||
void AddressExpression::appendIdentity(IdentityMode im,
|
||||
AddressExpression *identity_expression,
|
||||
std::vector<Address> &as,
|
||||
std::vector<AddressExpression> &es)
|
||||
{
|
||||
identity_expression->clear();
|
||||
if (im == IdentityMode::NONE) return;
|
||||
|
||||
// Copy id, id-mfct, id-mfct-v-t to identity_expression from the last address.
|
||||
identity_expression->trimToIdentity(im, as.back());
|
||||
|
||||
// Is this identity expression already in the list of address expressions?
|
||||
if (std::find(es.begin(), es.end(), *identity_expression) == es.end())
|
||||
{
|
||||
// No, then add it at the end.
|
||||
es.push_back(*identity_expression);
|
||||
}
|
||||
}
|
||||
|
||||
bool AddressExpression::operator==(const AddressExpression&ae) const
|
||||
{
|
||||
return id == ae.id &&
|
||||
has_wildcard == ae.has_wildcard&&
|
||||
mbus_primary == ae.mbus_primary &&
|
||||
mfct == ae.mfct &&
|
||||
version == ae.version &&
|
||||
type == ae.type &&
|
||||
filter_out == ae.filter_out;
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADDRESS_H_
|
||||
#define ADDRESS_H_
|
||||
|
||||
#include "util.h"
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
IdentityMode:
|
||||
|
||||
@ID: The default, only the id groups the meter content.
|
||||
@ID_MFCT: Used when you have two meters with the same id but different manufacturers.
|
||||
@FULL: Used when you want to fully separate meter content on id.mft.v.t
|
||||
@NONE: Do not separate any meters! This might lead to telegrams overwriting each others state.
|
||||
Use this when no state is to be kept in the wmbusmeters object.
|
||||
@INVALID: Cannot parse cmdline.
|
||||
*/
|
||||
enum class IdentityMode
|
||||
{
|
||||
ID,
|
||||
ID_MFCT,
|
||||
FULL,
|
||||
NONE,
|
||||
INVALID
|
||||
};
|
||||
|
||||
const char *toString(IdentityMode im);
|
||||
IdentityMode toIdentityMode(const char *s);
|
||||
|
||||
struct Address
|
||||
{
|
||||
std::string id; // p1 or 12345678 or non-compliant hex: 1234abcd
|
||||
uint16_t mfct {};
|
||||
uchar type {};
|
||||
uchar version {};
|
||||
|
||||
void decodeMfctFirst(const std::vector<uchar>::iterator &pos);
|
||||
void decodeIdFirst(const std::vector<uchar>::iterator &pos);
|
||||
|
||||
std::string str();
|
||||
static std::string concat(std::vector<Address> &addresses);
|
||||
};
|
||||
|
||||
struct AddressExpression
|
||||
{
|
||||
// An address expression is used to select which telegrams to decode for a driver.
|
||||
// An address expression is also used to select a specific meter to poll for data.
|
||||
// Example address: 12345678
|
||||
// Or fully qualified: 12345678.M=PII.T=1b.V=01
|
||||
// which means manufacturer triplet PII, type/media=0x1b, version=0x01
|
||||
// Or wildcards in id: 12*.T=16
|
||||
// which matches all cold water meters whose ids start with 12.
|
||||
// Or negated tests: 12345678.V!=66
|
||||
// which will decode all telegrams from 12345678 except those where the version is 0x66.
|
||||
// Or every telegram which is does not start with 12 and is not from ABB:
|
||||
// !12*.M!=ABB
|
||||
|
||||
std::string id; // p1 or 12345678 or non-compliant hex: 1234abcd
|
||||
bool has_wildcard {}; // The id contains a *
|
||||
bool mbus_primary {}; // Signals that the id is 0-250
|
||||
|
||||
uint16_t mfct { 0xffff }; // If 0xffff then any mfct matches this address.
|
||||
uchar version { 0xff }; // If 0xff then any version matches this address.
|
||||
uchar type { 0xff }; // If 0xff then any type matches this address.
|
||||
|
||||
bool filter_out {}; // Telegrams matching this rule should be filtered out!
|
||||
bool required {}; // If true, then this address expression must be matched!
|
||||
|
||||
AddressExpression() {}
|
||||
AddressExpression(Address &a) : id(a.id), mfct(a.mfct), version(a.version), type(a.type) { }
|
||||
bool operator==(const AddressExpression&) const;
|
||||
void clear();
|
||||
void trimToIdentity(IdentityMode im, Address &a);
|
||||
bool parse(const std::string &s);
|
||||
bool match(const std::string &id, uint16_t mfct, uchar version, uchar type);
|
||||
std::string str();
|
||||
static std::string concat(std::vector<AddressExpression> &address_expressions);
|
||||
static void appendIdentity(IdentityMode im,
|
||||
AddressExpression *identity_expression,
|
||||
std::vector<Address> &as,
|
||||
std::vector<AddressExpression> &es);
|
||||
};
|
||||
|
||||
/**
|
||||
isValidSequenceOfAddressExpressions:
|
||||
|
||||
Valid sequenes look like this:
|
||||
12345678
|
||||
12345678,22334455,34*
|
||||
12*.T=16,!*.M=XYZ
|
||||
!*.V=33
|
||||
*/
|
||||
bool isValidSequenceOfAddressExpressions(const std::string& s);
|
||||
std::vector<AddressExpression> splitAddressExpressions(const std::string &aes);
|
||||
bool flagToManufacturer(const char *s, uint16_t *out_mfct);
|
||||
std::string manufacturerFlag(int m_field);
|
||||
bool doesTelegramMatchExpressions(std::vector<Address> &addresses,
|
||||
std::vector<AddressExpression>& address_expressions,
|
||||
bool *used_wildcard);
|
||||
|
||||
#endif
|
|
@ -25,7 +25,6 @@
|
|||
#include"shell.h"
|
||||
#include"threads.h"
|
||||
#include"util.h"
|
||||
#include"version.h"
|
||||
#include"wmbus.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
|
194
src/cmdline.cc
194
src/cmdline.cc
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include"cmdline.h"
|
||||
#include"drivers.h"
|
||||
#include"meters.h"
|
||||
#include"util.h"
|
||||
|
||||
|
@ -59,27 +60,58 @@ shared_ptr<Configuration> parseCommandLine(int argc, char **argv)
|
|||
return parseNormalCommandLine(c, argc, argv);
|
||||
}
|
||||
|
||||
void enableEarlyLoggingFromCommandLine(int argc, char **argv)
|
||||
{
|
||||
int i = 1;
|
||||
// First find all logging flags, --silent --verbose --normal --debug
|
||||
while (argv[i] && argv[i][0] == '-')
|
||||
{
|
||||
if (!strcmp(argv[i], "--silent")) {
|
||||
i++;
|
||||
silentLogging(true);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--verbose")) {
|
||||
verboseEnabled(true);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--normal")) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--debug")) {
|
||||
verboseEnabled(true);
|
||||
debugEnabled(true);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--trace")) {
|
||||
verboseEnabled(true);
|
||||
debugEnabled(true);
|
||||
traceEnabled(true);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int argc, char **argv)
|
||||
{
|
||||
int i = 1;
|
||||
// First find all logging flags, --silent --verbose --normal --debug
|
||||
while (argv[i] && argv[i][0] == '-')
|
||||
{
|
||||
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
|
||||
c->need_help = true;
|
||||
return shared_ptr<Configuration>(c);
|
||||
}
|
||||
if (!strncmp(argv[i], "--device=", 9) || // Deprecated
|
||||
!strncmp(argv[i], "--overridedevice=", 17))
|
||||
{
|
||||
error("You can only use --overridedevice=xyz with --useconfig=xyz\n");
|
||||
}
|
||||
if (!strcmp(argv[i], "--silent")) {
|
||||
c->silent = true;
|
||||
i++;
|
||||
silentLogging(true);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--verbose")) {
|
||||
c->verbose = true;
|
||||
verboseEnabled(true);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
@ -91,6 +123,48 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
|
|||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--debug")) {
|
||||
c->debug = true;
|
||||
verboseEnabled(true);
|
||||
debugEnabled(true);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--trace")) {
|
||||
c->debug = true;
|
||||
c->trace = true;
|
||||
verboseEnabled(true);
|
||||
debugEnabled(true);
|
||||
traceEnabled(true);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Now do the rest of the arguments.
|
||||
i = 1;
|
||||
while (argv[i] && argv[i][0] == '-')
|
||||
{
|
||||
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help") || !strcmp(argv[i], "--help")) {
|
||||
c->need_help = true;
|
||||
return shared_ptr<Configuration>(c);
|
||||
}
|
||||
if (!strcmp(argv[i], "--silent") ||
|
||||
!strcmp(argv[i], "--verbose") ||
|
||||
!strcmp(argv[i], "--normal") ||
|
||||
!strcmp(argv[i], "--debug") ||
|
||||
!strcmp(argv[i], "--trace"))
|
||||
{
|
||||
// Handled already.
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(argv[i], "--device=", 9) || // Deprecated
|
||||
!strncmp(argv[i], "--overridedevice=", 17))
|
||||
{
|
||||
error("You can only use --overridedevice=xyz with --useconfig=xyz\n");
|
||||
}
|
||||
if (!strcmp(argv[i], "--version")) {
|
||||
c->version = true;
|
||||
return shared_ptr<Configuration>(c);
|
||||
|
@ -162,18 +236,6 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
|
|||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[i], "--debug")) {
|
||||
c->debug = true;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "--trace")) {
|
||||
c->debug = true;
|
||||
c->trace = true;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(argv[i], "--logtimestamps=", 16))
|
||||
{
|
||||
string ts = string(argv[i]+16);
|
||||
|
@ -451,6 +513,15 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
|
|||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(argv[i], "--metershell=", 13)) {
|
||||
string cmd = string(argv[i]+13);
|
||||
if (cmd == "") {
|
||||
error("The meter shell command cannot be empty.\n");
|
||||
}
|
||||
c->meter_shells.push_back(cmd);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(argv[i], "--alarmshell=", 13)) {
|
||||
string cmd = string(argv[i]+13);
|
||||
if (cmd == "") {
|
||||
|
@ -546,6 +617,15 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
|
|||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(argv[i], "--identitymode=", 15) && strlen(argv[i]) > 15) {
|
||||
c->identity_mode = toIdentityMode(argv[i]+15);
|
||||
if (c->identity_mode == IdentityMode::INVALID)
|
||||
{
|
||||
error("Not a valid identity mode. \"%s\"\n", argv[i]+15);
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(argv[i], "--resetafter=", 13) && strlen(argv[i]) > 13) {
|
||||
c->resetafter = parseTime(argv[i]+13);
|
||||
if (c->resetafter <= 0) {
|
||||
|
@ -572,6 +652,31 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
|
|||
i++;
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(argv[i], "--driversdir=", 13))
|
||||
{
|
||||
size_t len = strlen(argv[i]) - 13;
|
||||
c->drivers_dir = string(argv[i]+13, len);
|
||||
if (!checkIfDirExists(c->drivers_dir.c_str()))
|
||||
{
|
||||
error("You must supply a valid directory to --driversdir=<dir>\n");
|
||||
}
|
||||
i++;
|
||||
loadDriversFromDir(c->drivers_dir);
|
||||
continue;
|
||||
}
|
||||
if (!strncmp(argv[i], "--driver=", 9))
|
||||
{
|
||||
size_t len = strlen(argv[i]) - 9;
|
||||
string file_name = string(argv[i]+9, len);
|
||||
if (!checkFileExists(file_name.c_str()))
|
||||
{
|
||||
error("You must supply a valid file to --driver=<file>\n");
|
||||
}
|
||||
i++;
|
||||
loadDriver(file_name, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
error("Unknown option \"%s\"\n", argv[i]);
|
||||
}
|
||||
|
||||
|
@ -632,50 +737,31 @@ static shared_ptr<Configuration> parseNormalCommandLine(Configuration *c, int ar
|
|||
string bus;
|
||||
string name = argv[m*4+i+0];
|
||||
string driver = argv[m*4+i+1];
|
||||
string id = argv[m*4+i+2];
|
||||
string address_expressions = argv[m*4+i+2];
|
||||
string key = argv[m*4+i+3];
|
||||
|
||||
MeterInfo mi;
|
||||
mi.parse(name, driver, id, key);
|
||||
|
||||
if (!isValidSequenceOfAddressExpressions(address_expressions))
|
||||
{
|
||||
error("Not a valid meter id nor a valid sequence of match expression \"%s\"\n", address_expressions.c_str());
|
||||
}
|
||||
|
||||
mi.parse(name, driver, address_expressions, key);
|
||||
mi.poll_interval = c->pollinterval;
|
||||
mi.identity_mode = c->identity_mode;
|
||||
|
||||
if (!isValidKey(key, mi))
|
||||
{
|
||||
error("Not a valid meter key \"%s\"\n", key.c_str());
|
||||
}
|
||||
|
||||
if (mi.driver_name.str() == "")
|
||||
{
|
||||
error("Not a valid meter driver \"%s\"\n", driver.c_str());
|
||||
}
|
||||
|
||||
//LinkModeSet default_modes = toMeterLinkModeSet(mi.driver);
|
||||
|
||||
/*
|
||||
if (default_modes.has(LinkMode::MBUS))
|
||||
{
|
||||
// MBus primary address 0-250
|
||||
// secondary hex address iiiiiiiimmmmvvmm
|
||||
}
|
||||
else
|
||||
{
|
||||
// WMBus ids are 8 hex digits iiiiiiii
|
||||
if (!isValidMatchExpressions(id, true)) error("Not a valid id nor a valid meter match expression \"%s\"\n", id.c_str());
|
||||
}
|
||||
if (!isValidKey(key, mi)) error("Not a valid meter key \"%s\"\n", key.c_str());
|
||||
*/
|
||||
|
||||
c->meters.push_back(mi);
|
||||
|
||||
// Check if the devices can listen to the meter link mode(s).
|
||||
/*
|
||||
Ignore this check for now until all meters have been refactored.
|
||||
if (!default_modes.hasAll(mi.link_modes))
|
||||
{
|
||||
string want = mi.link_modes.hr();
|
||||
string has = default_modes.hr();
|
||||
error("(cmdline) cannot set link modes to: %s because meter %s only transmits on: %s\n",
|
||||
want.c_str(), mi.driverName().str().c_str(), has.c_str());
|
||||
}
|
||||
string modeshr = mi.link_modes.hr();
|
||||
debug("(cmdline) setting link modes to %s for meter %s\n",
|
||||
mi.link_modes.hr().c_str(), name.c_str());
|
||||
*/
|
||||
}
|
||||
|
||||
return shared_ptr<Configuration>(c);
|
||||
|
|
|
@ -27,5 +27,6 @@
|
|||
using namespace std;
|
||||
|
||||
shared_ptr<Configuration> parseCommandLine(int argc, char **argv);
|
||||
void enableEarlyLoggingFromCommandLine(int argc, char **argv);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include"config.h"
|
||||
#include"drivers.h"
|
||||
#include"meters.h"
|
||||
#include"units.h"
|
||||
|
||||
|
@ -52,11 +53,13 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
|
|||
string bus;
|
||||
string name;
|
||||
string driver = "auto";
|
||||
string id;
|
||||
string address_expressions;
|
||||
string key = "";
|
||||
string linkmodes;
|
||||
int poll_interval = 0;
|
||||
IdentityMode identity_mode {};
|
||||
vector<string> telegram_shells;
|
||||
vector<string> meter_shells;
|
||||
vector<string> alarm_shells;
|
||||
vector<string> extra_constant_fields;
|
||||
vector<string> extra_calculated_fields;
|
||||
|
@ -106,7 +109,7 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
|
|||
else
|
||||
if (p.first == "driver") driver = p.second;
|
||||
else
|
||||
if (p.first == "id") id = p.second;
|
||||
if (p.first == "id") address_expressions = p.second;
|
||||
else
|
||||
if (p.first == "key")
|
||||
{
|
||||
|
@ -127,10 +130,23 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
|
|||
}
|
||||
}
|
||||
else
|
||||
if (p.first == "identitymode") {
|
||||
identity_mode = toIdentityMode(p.second.c_str());
|
||||
|
||||
if (identity_mode == IdentityMode::INVALID)
|
||||
{
|
||||
error("Invalid identity mode: \"%s\"!\n", p.second.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
if (p.first == "shell") {
|
||||
telegram_shells.push_back(p.second);
|
||||
}
|
||||
else
|
||||
if (p.first == "metershell") {
|
||||
meter_shells.push_back(p.second);
|
||||
}
|
||||
else
|
||||
if (p.first == "alarmshell") {
|
||||
alarm_shells.push_back(p.second);
|
||||
}
|
||||
|
@ -170,36 +186,28 @@ void parseMeterConfig(Configuration *c, vector<char> &buf, string file)
|
|||
|
||||
MeterInfo mi;
|
||||
|
||||
mi.parse(name, driver, id, key); // sets driver, extras, name, bus, bps, link_modes, ids, name, key
|
||||
mi.poll_interval = poll_interval;
|
||||
|
||||
/*
|
||||
Ignore link mode checking until all drivers have been refactored.
|
||||
LinkModeSet default_modes = toMeterLinkModeSet(mi.driver);
|
||||
if (!default_modes.hasAll(mi.link_modes))
|
||||
if (!isValidSequenceOfAddressExpressions(address_expressions))
|
||||
{
|
||||
string want = mi.link_modes.hr();
|
||||
string has = default_modes.hr();
|
||||
error("(cmdline) cannot set link modes to: %s because meter %s only transmits on: %s\n",
|
||||
want.c_str(), mi.driverName().str().c_str(), has.c_str());
|
||||
}
|
||||
string modeshr = mi.link_modes.hr();
|
||||
debug("(cmdline) setting link modes to %s for meter %s\n",
|
||||
mi.link_modes.hr().c_str(), name.c_str());
|
||||
*/
|
||||
if (!isValidMatchExpressions(id, true)) {
|
||||
warning("Not a valid meter id nor a valid meter match expression \"%s\"\n", id.c_str());
|
||||
warning("In config, not a valid meter id nor a valid sequence of match expression \"%s\"\n", address_expressions.c_str());
|
||||
use = false;
|
||||
}
|
||||
if (!isValidKey(key, mi)) {
|
||||
warning("Not a valid meter key \"%s\"\n", key.c_str());
|
||||
|
||||
mi.parse(name, driver, address_expressions, key); // sets driver, extras, name, bus, bps, link_modes, ids, name, key
|
||||
mi.poll_interval = poll_interval;
|
||||
mi.identity_mode = identity_mode;
|
||||
|
||||
if (!isValidKey(key, mi))
|
||||
{
|
||||
warning("In config, not a valid meter key in config \"%s\"\n", key.c_str());
|
||||
use = false;
|
||||
}
|
||||
if (use) {
|
||||
|
||||
if (use)
|
||||
{
|
||||
mi.extra_constant_fields = extra_constant_fields;
|
||||
mi.extra_calculated_fields = extra_calculated_fields;
|
||||
mi.shells = telegram_shells;
|
||||
mi.idsc = toIdsCommaSeparated(mi.ids);
|
||||
mi.meter_shells = meter_shells;
|
||||
mi.selected_fields = selected_fields;
|
||||
c->meters.push_back(mi);
|
||||
}
|
||||
|
@ -636,6 +644,11 @@ void handleShell(Configuration *c, string cmdline)
|
|||
c->telegram_shells.push_back(cmdline);
|
||||
}
|
||||
|
||||
void handleMeterShell(Configuration *c, string cmdline)
|
||||
{
|
||||
c->meter_shells.push_back(cmdline);
|
||||
}
|
||||
|
||||
void handleAlarmShell(Configuration *c, string cmdline)
|
||||
{
|
||||
c->alarm_shells.push_back(cmdline);
|
||||
|
@ -668,12 +681,14 @@ shared_ptr<Configuration> loadConfiguration(string root, ConfigOverrides overrid
|
|||
string conf_dir = root;
|
||||
string conf_file = root+"/etc/wmbusmeters.conf";
|
||||
string conf_meter_dir = root+"/etc/wmbusmeters.d";
|
||||
string conf_drivers_dir = root+"/etc/wmbusmeters.drivers.d";
|
||||
|
||||
if (!checkFileExists(conf_file.c_str()))
|
||||
{
|
||||
conf_dir = root+"/etc";
|
||||
conf_file = root+"/wmbusmeters.conf";
|
||||
conf_meter_dir = root+"/wmbusmeters.d";
|
||||
conf_drivers_dir = root+"/wmbusmeters.drivers.d";
|
||||
}
|
||||
|
||||
debug("(config) loading %s\n", conf_file.c_str());
|
||||
|
@ -714,6 +729,7 @@ shared_ptr<Configuration> loadConfiguration(string root, ConfigOverrides overrid
|
|||
else if (p.first == "selectfields") handleSelectedFields(c, p.second);
|
||||
else if (p.first == "shell") handleShell(c, p.second);
|
||||
else if (p.first == "resetafter") handleResetAfter(c, p.second);
|
||||
else if (p.first == "metershell") handleMeterShell(c, p.second);
|
||||
else if (p.first == "alarmshell") handleAlarmShell(c, p.second);
|
||||
else if (startsWith(p.first, "json_") ||
|
||||
startsWith(p.first, "field_"))
|
||||
|
@ -793,6 +809,8 @@ shared_ptr<Configuration> loadConfiguration(string root, ConfigOverrides overrid
|
|||
handleLogfile(c, overrides.logfile_override);
|
||||
}
|
||||
|
||||
loadDriversFromDir(conf_drivers_dir);
|
||||
|
||||
return shared_ptr<Configuration>(c);
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ struct Configuration
|
|||
ConfigOverrides overrides;
|
||||
bool useconfig {};
|
||||
std::string config_root;
|
||||
std::string drivers_dir;
|
||||
bool need_help {};
|
||||
bool silent {};
|
||||
bool verbose {};
|
||||
|
@ -98,9 +99,11 @@ struct Configuration
|
|||
bool json {};
|
||||
bool pretty_print_json {};
|
||||
int pollinterval {}; // Time between polling of mbus meters.
|
||||
IdentityMode identity_mode {}; // How to group meters identities into state objects.
|
||||
bool fields {};
|
||||
char separator { ';' };
|
||||
std::vector<std::string> telegram_shells;
|
||||
std::vector<std::string> meter_shells;
|
||||
std::vector<std::string> alarm_shells;
|
||||
int alarm_timeout {}; // Maximum number of seconds between dongle receiving two telegrams.
|
||||
std::string alarm_expected_activity; // Only warn when within these time periods.
|
||||
|
|
1342
src/driver_abbb23.cc
1342
src/driver_abbb23.cc
Plik diff jest za duży
Load Diff
|
@ -41,7 +41,7 @@ namespace
|
|||
"The total gas consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -53,7 +53,7 @@ namespace
|
|||
"The current gas flow.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -64,7 +64,7 @@ namespace
|
|||
"The current temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
"Date time when previous billing period ended.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
|
@ -87,7 +87,7 @@ namespace
|
|||
"The total gas consumption recorded when the previous billing period ended.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -54,7 +54,7 @@ namespace
|
|||
"Current power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::PowerW)
|
||||
|
@ -65,7 +65,7 @@ namespace
|
|||
"The total energy production recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0E833C"))
|
||||
);
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
"Current power production.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0BAB3C"))
|
||||
);
|
||||
|
@ -85,7 +85,7 @@ namespace
|
|||
"Voltage at phase L1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0AFDC9FC01"))
|
||||
);
|
||||
|
@ -95,7 +95,7 @@ namespace
|
|||
"Voltage at phase L2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0AFDC9FC02"))
|
||||
);
|
||||
|
@ -105,7 +105,7 @@ namespace
|
|||
"Voltage at phase L3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0AFDC9FC03"))
|
||||
);
|
||||
|
@ -124,7 +124,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter on tariff 1.",
|
||||
DEFAULT_PRINT_PROPERTIES, // ,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -136,7 +136,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter on tariff 2.",
|
||||
DEFAULT_PRINT_PROPERTIES, // ,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -148,7 +148,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter on tariff 3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -160,7 +160,7 @@ namespace
|
|||
"The total energy production recorded by this meter on tariff 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("8E10833C"))
|
||||
);
|
||||
|
@ -170,7 +170,7 @@ namespace
|
|||
"The total energy production recorded by this meter on tariff 2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("8E20833C"))
|
||||
);
|
||||
|
@ -180,7 +180,7 @@ namespace
|
|||
"The total energy production recorded by this meter on tariff 3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("8E30833C"))
|
||||
);
|
||||
|
@ -190,7 +190,7 @@ namespace
|
|||
"The maximum demand indicator (maximum 15-min average power consumption recorded this month).",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
|
|
@ -56,12 +56,14 @@ namespace
|
|||
vector<uchar> content;
|
||||
t->extractPayload(&content);
|
||||
|
||||
if (content.size() < 4) return;
|
||||
|
||||
map<string,pair<int,DVEntry>> vendor_values;
|
||||
|
||||
string total;
|
||||
strprintf(&total, "%02x%02x%02x%02x", content[0], content[1], content[2], content[3]);
|
||||
|
||||
vendor_values["0413"] = { 25, DVEntry(25, DifVifKey("0413"), MeasurementType::Instantaneous, 0x13, {}, 0, 0, 0, total) };
|
||||
vendor_values["0413"] = { 25, DVEntry(25, DifVifKey("0413"), MeasurementType::Instantaneous, 0x13, {}, {}, 0, 0, 0, total) };
|
||||
int offset;
|
||||
string key;
|
||||
if(findKey(MeasurementType::Instantaneous, VIFRange::Volume, 0, 0, &key, &vendor_values))
|
||||
|
|
|
@ -119,7 +119,7 @@ namespace
|
|||
string total;
|
||||
strprintf(&total, "%02x%02x%02x%02x", content[i+0], content[i+1], content[i+2], content[i+3]);
|
||||
int offset = i-1+t->header_size;
|
||||
vendor_values["0413"] = {offset, DVEntry(offset, DifVifKey("0413"), MeasurementType::Instantaneous, 0x13, {}, 0, 0, 0, total) };
|
||||
vendor_values["0413"] = {offset, DVEntry(offset, DifVifKey("0413"), MeasurementType::Instantaneous, 0x13, {}, {}, 0, 0, 0, total) };
|
||||
double total_water_consumption_m3 {};
|
||||
extractDVdouble(&vendor_values, "0413", &offset, &total_water_consumption_m3);
|
||||
total = "*** 10-"+total+" total consumption (%f m3)";
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace
|
|||
string total;
|
||||
strprintf(&total, "%02x%02x%02x%02x", content[i+0], content[i+1], content[i+2], content[i+3]);
|
||||
int offset = i-1+t->header_size;
|
||||
vendor_values["0413"] = {offset, DVEntry(offset, DifVifKey("0413"), MeasurementType::Instantaneous, 0x13, {}, 0, 0, 0, total) };
|
||||
vendor_values["0413"] = {offset, DVEntry(offset, DifVifKey("0413"), MeasurementType::Instantaneous, 0x13, {}, {}, 0, 0, 0, total) };
|
||||
double tmp = 0;
|
||||
extractDVdouble(&vendor_values, "0413", &offset, &tmp);
|
||||
// Single tick seems to be 1/3 of a m3. Divide by 3 and keep a single decimal.
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace
|
|||
uchar season_start_date_lo = content[1];
|
||||
uchar season_start_date_hi = content[0];
|
||||
string season_start_date = dateToString(season_start_date_lo, season_start_date_hi);
|
||||
setStringValue("season_start_date", season_start_date);
|
||||
setStringValue("season_start_date", season_start_date, NULL);
|
||||
|
||||
// Previous season total allocation
|
||||
uchar prev_lo = content[4];
|
||||
|
@ -126,7 +126,7 @@ namespace
|
|||
uchar esb_date_lo = content[6];
|
||||
uchar esb_date_hi = content[7];
|
||||
string esb_date = dateToString(esb_date_lo, esb_date_hi);
|
||||
setStringValue("esb_date", esb_date);
|
||||
setStringValue("esb_date", esb_date, NULL);
|
||||
|
||||
// Current season allocation
|
||||
uchar curr_lo = content[8];
|
||||
|
@ -138,7 +138,7 @@ namespace
|
|||
uchar date_curr_lo = content[10];
|
||||
uchar date_curr_hi = content[11];
|
||||
string current_date = dateToString(date_curr_lo, date_curr_hi);
|
||||
setStringValue("current_date", current_date);
|
||||
setStringValue("current_date", current_date, NULL);
|
||||
|
||||
// Previous season average temperature
|
||||
double temp_room_prev_avg_frac = content[12];
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"",
|
||||
{
|
||||
|
@ -95,7 +95,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -106,7 +106,7 @@ namespace
|
|||
"Heat cost allocation at the most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -118,7 +118,7 @@ namespace
|
|||
"The heat cost allocation at set date #.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -80,7 +80,7 @@ namespace
|
|||
"Water consumption at the # billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -100,7 +100,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace
|
|||
t->addSpecialExplanation(4+t->header_size, 2, KindOfData::CONTENT, Understanding::FULL, msg.c_str());
|
||||
|
||||
string device_date = tostrprintf("20%02x-%02x-%02x", content[39], content[39-1], content[39-2]);
|
||||
setStringValue("device_date", device_date);
|
||||
setStringValue("device_date", device_date, NULL);
|
||||
|
||||
msg = tostrprintf("*** %02X%02X%02X \"device_date\":\"%s\"", content[39-2], content[39-1], content[39],
|
||||
device_date.c_str());
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace
|
|||
"The total heat energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -83,7 +83,7 @@ namespace
|
|||
"The total heating media volume recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -101,7 +101,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::DecimalsToString,
|
||||
Translate::MapType::DecimalsToString,
|
||||
AlwaysTrigger, MaskBits(9999),
|
||||
"OK",
|
||||
{
|
||||
|
@ -152,7 +152,7 @@ namespace
|
|||
"The total heat energy consumption recorded at end of previous month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(32+i))
|
||||
|
@ -169,7 +169,7 @@ namespace
|
|||
tostrprintf("Previous month %d last date.", i+1),
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(32+i))
|
||||
|
@ -184,7 +184,7 @@ namespace
|
|||
"The total heat energy consumption at the due date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(8))
|
||||
|
@ -206,7 +206,7 @@ namespace
|
|||
"The current heat media volume flow.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -217,7 +217,7 @@ namespace
|
|||
"The current power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::PowerW)
|
||||
|
@ -228,7 +228,7 @@ namespace
|
|||
"The total heat energy consumption recorded at end of last month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(32))
|
||||
|
@ -249,7 +249,7 @@ namespace
|
|||
"Maximum power consumption last month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(StorageNr(32))
|
||||
|
@ -262,7 +262,7 @@ namespace
|
|||
"The current forward heat media temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -273,7 +273,7 @@ namespace
|
|||
"The current return heat media temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
|
@ -284,21 +284,20 @@ namespace
|
|||
// Test: Heat c5isf 55445555 NOKEY
|
||||
|
||||
// telegram=|E544496A55554455880D7A320200002F2F_04060000000004130000000002FD17240084800106000000008280016C2124C480010600000080C280016CFFFF84810106000000808281016CFFFFC481010600000080C281016CFFFF84820106000000808282016CFFFFC482010600000080C282016CFFFF84830106000000808283016CFFFFC483010600000080C283016CFFFF84840106000000808284016CFFFFC484010600000080C284016CFFFF84850106000000808285016CFFFFC485010600000080C285016CFFFF84860106000000808286016CFFFFC486010600000080C286016CFFFF|
|
||||
// {"media":"heat/cooling load","meter":"c5isf","name":"Heat","id":"55445555","total_energy_consumption_kwh":0,"total_volume_m3":0,"status":"ERROR REVERSE_FLOW SUPPLY_SENSOR_INTERRUPTED","prev_1_month":"2017-04-01","prev_2_month":"2127-15-31","prev_3_month":"2127-15-31","prev_4_month":"2127-15-31","prev_5_month":"2127-15-31","prev_6_month":"2127-15-31","prev_7_month":"2127-15-31","prev_8_month":"2127-15-31","prev_9_month":"2127-15-31","prev_10_month":"2127-15-31","prev_11_month":"2127-15-31","prev_12_month":"2127-15-31","prev_13_month":"2127-15-31","prev_14_month":"2127-15-31","prev_1_month_kwh":0,"prev_2_month_kwh":2147483648,"prev_3_month_kwh":2147483648,"prev_4_month_kwh":2147483648,"prev_5_month_kwh":2147483648,"prev_6_month_kwh":2147483648,"prev_7_month_kwh":2147483648,"prev_8_month_kwh":2147483648,"prev_9_month_kwh":2147483648,"prev_10_month_kwh":2147483648,"prev_11_month_kwh":2147483648,"prev_12_month_kwh":2147483648,"prev_13_month_kwh":2147483648,"prev_14_month_kwh":2147483648,"total_energy_consumption_last_month_kwh":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// {"media":"heat/cooling load","meter":"c5isf","name":"Heat","id":"55445555","total_energy_consumption_kwh":0,"total_volume_m3":0,"status":"ERROR REVERSE_FLOW SUPPLY_SENSOR_INTERRUPTED","prev_1_month":"2017-04-01","prev_2_month":"2127-15-31","prev_3_month":"2127-15-31","prev_4_month":"2127-15-31","prev_5_month":"2127-15-31","prev_6_month":"2127-15-31","prev_7_month":"2127-15-31","prev_8_month":"2127-15-31","prev_9_month":"2127-15-31","prev_10_month":"2127-15-31","prev_11_month":"2127-15-31","prev_12_month":"2127-15-31","prev_13_month":"2127-15-31","prev_14_month":"2127-15-31","prev_1_month_kwh":0,"prev_2_month_kwh":-2147483648,"prev_3_month_kwh":-2147483648,"prev_4_month_kwh":-2147483648,"prev_5_month_kwh":-2147483648,"prev_6_month_kwh":-2147483648,"prev_7_month_kwh":-2147483648,"prev_8_month_kwh":-2147483648,"prev_9_month_kwh":-2147483648,"prev_10_month_kwh":-2147483648,"prev_11_month_kwh":-2147483648,"prev_12_month_kwh":-2147483648,"prev_13_month_kwh":-2147483648,"prev_14_month_kwh":-2147483648,"total_energy_consumption_last_month_kwh":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Heat;55445555;0;0;ERROR REVERSE_FLOW SUPPLY_SENSOR_INTERRUPTED;1111-11-11 11:11.11
|
||||
|
||||
// Type T1A2 telegram:
|
||||
// telegram=|DA44496A5555445588077A320200002F2F_04140000000084800114000000008280016C2124C480011400000080C280016CFFFF84810114000000808281016CFFFFC481011400000080C281016CFFFF84820114000000808282016CFFFFC482011400000080C282016CFFFF84830114000000808283016CFFFFC483011400000080C283016CFFFF84840114000000808284016CFFFFC484011400000080C284016CFFFF84850114000000808285016CFFFFC485011400000080C285016CFFFF84860114000000808286016CFFFFC486011400000080C286016CFFFF|
|
||||
// {"media":"water","meter":"c5isf","name":"Heat","id":"55445555","total_energy_consumption_kwh":0,"total_volume_m3":0,"status":"ERROR","prev_1_month":"2017-04-01","prev_2_month":"2127-15-31","prev_3_month":"2127-15-31","prev_4_month":"2127-15-31","prev_5_month":"2127-15-31","prev_6_month":"2127-15-31","prev_7_month":"2127-15-31","prev_8_month":"2127-15-31","prev_9_month":"2127-15-31","prev_10_month":"2127-15-31","prev_11_month":"2127-15-31","prev_12_month":"2127-15-31","prev_13_month":"2127-15-31","prev_14_month":"2127-15-31","prev_1_month_m3":0,"prev_2_month_m3":21474836.48,"prev_3_month_m3":21474836.48,"prev_4_month_m3":21474836.48,"prev_5_month_m3":21474836.48,"prev_6_month_m3":21474836.48,"prev_7_month_m3":21474836.48,"prev_8_month_m3":21474836.48,"prev_9_month_m3":21474836.48,"prev_10_month_m3":21474836.48,"prev_11_month_m3":21474836.48,"prev_12_month_m3":21474836.48,"prev_13_month_m3":21474836.48,"prev_14_month_m3":21474836.48,"total_energy_consumption_last_month_kwh":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// {"id": "55445555","media": "water","meter": "c5isf","name": "Heat","prev_10_month": "2127-15-31","prev_10_month_kwh":-2147483648,"prev_10_month_m3":-21474836.48,"prev_11_month": "2127-15-31","prev_11_month_kwh":-2147483648,"prev_11_month_m3":-21474836.48,"prev_12_month": "2127-15-31","prev_12_month_kwh":-2147483648,"prev_12_month_m3":-21474836.48,"prev_13_month": "2127-15-31","prev_13_month_kwh":-2147483648,"prev_13_month_m3":-21474836.48,"prev_14_month": "2127-15-31","prev_14_month_kwh":-2147483648,"prev_14_month_m3":-21474836.48,"prev_1_month": "2017-04-01","prev_1_month_kwh": 0,"prev_1_month_m3": 0,"prev_2_month": "2127-15-31","prev_2_month_kwh":-2147483648,"prev_2_month_m3":-21474836.48,"prev_3_month": "2127-15-31","prev_3_month_kwh":-2147483648,"prev_3_month_m3":-21474836.48,"prev_4_month": "2127-15-31","prev_4_month_kwh":-2147483648,"prev_4_month_m3":-21474836.48,"prev_5_month": "2127-15-31","prev_5_month_kwh":-2147483648,"prev_5_month_m3":-21474836.48,"prev_6_month": "2127-15-31","prev_6_month_kwh":-2147483648,"prev_6_month_m3":-21474836.48,"prev_7_month": "2127-15-31","prev_7_month_kwh":-2147483648,"prev_7_month_m3":-21474836.48,"prev_8_month": "2127-15-31","prev_8_month_kwh":-2147483648,"prev_8_month_m3":-21474836.48,"prev_9_month": "2127-15-31","prev_9_month_kwh":-2147483648,"prev_9_month_m3":-21474836.48,"status": "ERROR","timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 0,"total_energy_consumption_last_month_kwh": 0,"total_volume_m3": 0}
|
||||
// |Heat;55445555;0;0;ERROR;1111-11-11 11:11.11
|
||||
|
||||
// Type T1B telegram:
|
||||
// telegram=|5E44496A5555445588047A0A0050052F2F_04061A0000000413C20800008404060000000082046CC121043BA4000000042D1900000002591216025DE21002FD17000084800106000000008280016CC121948001AE25000000002F2F2F2F2F2F|
|
||||
// {"media":"heat","meter":"c5isf","name":"Heat","id":"55445555","total_energy_consumption_kwh":26,"total_volume_m3":2.242,"status":"OK","prev_1_month":"2022-01-01","prev_2_month":"2127-15-31","prev_3_month":"2127-15-31","prev_4_month":"2127-15-31","prev_5_month":"2127-15-31","prev_6_month":"2127-15-31","prev_7_month":"2127-15-31","prev_8_month":"2127-15-31","prev_9_month":"2127-15-31","prev_10_month":"2127-15-31","prev_11_month":"2127-15-31","prev_12_month":"2127-15-31","prev_13_month":"2127-15-31","prev_14_month":"2127-15-31","prev_1_month_kwh":0,"prev_2_month_kwh":2147483648,"prev_3_month_kwh":2147483648,"prev_4_month_kwh":2147483648,"prev_5_month_kwh":2147483648,"prev_6_month_kwh":2147483648,"prev_7_month_kwh":2147483648,"prev_8_month_kwh":2147483648,"prev_9_month_kwh":2147483648,"prev_10_month_kwh":2147483648,"prev_11_month_kwh":2147483648,"prev_12_month_kwh":2147483648,"prev_13_month_kwh":2147483648,"prev_14_month_kwh":2147483648,"prev_2_month_m3":21474836.48,"prev_3_month_m3":21474836.48,"prev_4_month_m3":21474836.48,"prev_5_month_m3":21474836.48,"prev_6_month_m3":21474836.48,"prev_7_month_m3":21474836.48,"prev_8_month_m3":21474836.48,"prev_9_month_m3":21474836.48,"prev_10_month_m3":21474836.48,"prev_11_month_m3":21474836.48,"prev_12_month_m3":21474836.48,"prev_13_month_m3":21474836.48,"prev_14_month_m3":21474836.48,"due_energy_consumption_kwh":0,"due_date":"2022-01-01","volume_flow_m3h":0.164,"power_kw":2.5,"total_energy_consumption_last_month_kwh":0,"max_power_last_month_kw":0,"flow_temperature_c":56.5,"return_temperature_c":43.22,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// {"due_date": "2022-01-01","due_energy_consumption_kwh": 0,"flow_temperature_c": 56.5,"id": "55445555","max_power_last_month_kw": 0,"media": "heat","meter": "c5isf","name": "Heat","power_kw": 2.5,"prev_10_month": "2127-15-31","prev_10_month_kwh":-2147483648,"prev_10_month_m3":-21474836.48,"prev_11_month": "2127-15-31","prev_11_month_kwh":-2147483648,"prev_11_month_m3":-21474836.48,"prev_12_month": "2127-15-31","prev_12_month_kwh":-2147483648,"prev_12_month_m3":-21474836.48,"prev_13_month": "2127-15-31","prev_13_month_kwh":-2147483648,"prev_13_month_m3":-21474836.48,"prev_14_month": "2127-15-31","prev_14_month_kwh":-2147483648,"prev_14_month_m3":-21474836.48,"prev_1_month": "2022-01-01","prev_1_month_kwh": 0,"prev_1_month_m3": 0,"prev_2_month": "2127-15-31","prev_2_month_kwh":-2147483648,"prev_2_month_m3":-21474836.48,"prev_3_month": "2127-15-31","prev_3_month_kwh":-2147483648,"prev_3_month_m3":-21474836.48,"prev_4_month": "2127-15-31","prev_4_month_kwh":-2147483648,"prev_4_month_m3":-21474836.48,"prev_5_month": "2127-15-31","prev_5_month_kwh":-2147483648,"prev_5_month_m3":-21474836.48,"prev_6_month": "2127-15-31","prev_6_month_kwh":-2147483648,"prev_6_month_m3":-21474836.48,"prev_7_month": "2127-15-31","prev_7_month_kwh":-2147483648,"prev_7_month_m3":-21474836.48,"prev_8_month": "2127-15-31","prev_8_month_kwh":-2147483648,"prev_8_month_m3":-21474836.48,"prev_9_month": "2127-15-31","prev_9_month_kwh":-2147483648,"prev_9_month_m3":-21474836.48,"return_temperature_c": 43.22,"status": "OK","timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 26,"total_energy_consumption_last_month_kwh": 0,"total_volume_m3": 2.242,"volume_flow_m3h": 0.164}
|
||||
// |Heat;55445555;26;2.242;OK;1111-11-11 11:11.11
|
||||
|
||||
// Test: Heat c5isf 32002044 NOKEY
|
||||
|
||||
// Test telegram with max_power_last_month_kwh which is non-zero
|
||||
// telegram=|5E44496A4420003288047AFC0050052F2F_0406D00E00000413B28A05008404060000000082046CC121043B00000000042D000000000259E719025D051402FD17000084800106C00C00008280016CC125948001AE25090000002F2F2F2F2F2F|
|
||||
// {"media":"heat","meter":"c5isf","name":"Heat","id":"32002044","total_energy_consumption_kwh":3792,"total_volume_m3":363.186,"status":"OK","prev_1_month":"2022-05-01","prev_1_month_kwh":3264,"due_energy_consumption_kwh":0,"due_date":"2022-01-01","volume_flow_m3h":0,"power_kw":0,"total_energy_consumption_last_month_kwh":3264,"max_power_last_month_kw":9,"flow_temperature_c":66.31,"return_temperature_c":51.25,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("software_version");
|
||||
addOptionalLibraryFields("software_version");
|
||||
|
||||
addStringField(
|
||||
"status",
|
||||
|
@ -51,7 +51,7 @@ namespace
|
|||
"The current temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -62,7 +62,7 @@ namespace
|
|||
"The average temperature over the last hour.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -77,7 +77,7 @@ namespace
|
|||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DigitalInput),
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("BATTERY", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("BATTERY", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xffff)))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace
|
|||
string prevs;
|
||||
strprintf(&prevs, "%02x%02x", prev_lo, prev_hi);
|
||||
int offset = t->parsed.size()+3;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, 0, 0, 0, prevs) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, {}, 0, 0, 0, prevs) };
|
||||
Explanation pe(offset, 2, prevs, KindOfData::CONTENT, Understanding::FULL);
|
||||
t->explanations.push_back(pe);
|
||||
t->addMoreExplanation(offset, " energy used in previous billing period (%f KWH)", prev);
|
||||
|
@ -92,7 +92,7 @@ namespace
|
|||
string currs;
|
||||
strprintf(&currs, "%02x%02x", curr_lo, curr_hi);
|
||||
offset = t->parsed.size()+7;
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, 0, 0, 0, currs) };
|
||||
vendor_values["0215"] = { offset, DVEntry(offset, DifVifKey("0215"), MeasurementType::Instantaneous, 0x15, {}, {}, 0, 0, 0, currs) };
|
||||
Explanation ce(offset, 2, currs, KindOfData::CONTENT, Understanding::FULL);
|
||||
t->explanations.push_back(ce);
|
||||
t->addMoreExplanation(offset, " energy used in current billing period (%f KWH)", curr);
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -61,7 +61,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
Copyright (C) 2023-2024 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DRIVER_LOADER_H_
|
||||
#define DRIVER_LOADER_H_
|
||||
|
||||
#include "meters_common_implementation.h"
|
||||
|
||||
struct DriverDynamic : public virtual MeterCommonImplementation
|
||||
{
|
||||
DriverDynamic(MeterInfo &mi, DriverInfo &di);
|
||||
~DriverDynamic();
|
||||
static bool load(DriverInfo *di, const string &name, const char *content);
|
||||
static XMQProceed add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *di);
|
||||
static XMQProceed add_use(XMQDoc *doc, XMQNode *field, DriverDynamic *dd);
|
||||
static XMQProceed add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *dd);
|
||||
static XMQProceed add_match(XMQDoc *doc, XMQNode *match, DriverDynamic *dd);
|
||||
static XMQProceed add_combinable(XMQDoc *doc, XMQNode *match, DriverDynamic *dd);
|
||||
|
||||
static XMQProceed add_lookup(XMQDoc *doc, XMQNode *lookup, DriverDynamic *dd);
|
||||
static XMQProceed add_map(XMQDoc *doc, XMQNode *map, DriverDynamic *dd);
|
||||
|
||||
const string &fileName() { return file_name_; }
|
||||
|
||||
private:
|
||||
|
||||
string file_name_;
|
||||
FieldMatcher *tmp_matcher_;
|
||||
Translate::Lookup *tmp_lookup_;
|
||||
Translate::Rule *tmp_rule_;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -41,7 +41,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -52,7 +52,7 @@ namespace
|
|||
"Current power consumption at phase 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF01"))
|
||||
);
|
||||
|
@ -62,7 +62,7 @@ namespace
|
|||
"Current power consumption at phase 2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF02"))
|
||||
);
|
||||
|
@ -72,7 +72,7 @@ namespace
|
|||
"Current power consumption at phase 3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF03"))
|
||||
);
|
||||
|
@ -92,7 +92,7 @@ namespace
|
|||
"Calculated sum of power consumption of all phases.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
|
|
@ -40,14 +40,14 @@ namespace
|
|||
"Meter status. Includes both meter error field and tpl status field.",
|
||||
PrintProperty::STATUS | PrintProperty::INCLUDE_TPL_STATUS);
|
||||
|
||||
addOptionalCommonFields("on_time_h");
|
||||
addOptionalLibraryFields("on_time_h");
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"total_energy_consumption",
|
||||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -58,7 +58,7 @@ namespace
|
|||
"Current power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -69,7 +69,7 @@ namespace
|
|||
"The total energy production recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace
|
|||
{
|
||||
setMfctTPLStatusBits(
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xe0))
|
||||
.set(DefaultMessage("OK"))
|
||||
.add(Translate::Map(0x04 ,"RTC_INVALID", TestBit::Set))));
|
||||
|
@ -54,7 +54,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -90,7 +90,7 @@ namespace
|
|||
"Number of times the smoke alarm has triggered.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(SubUnitNr(1))
|
||||
|
@ -121,7 +121,7 @@ namespace
|
|||
"Time the smoke alarm has been removed.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(SubUnitNr(1))
|
||||
|
@ -145,7 +145,7 @@ namespace
|
|||
"Number of times the smoke alarm has been removed.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(SubUnitNr(1))
|
||||
|
@ -169,7 +169,7 @@ namespace
|
|||
"Number of times the test button has been pressed.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(SubUnitNr(1))
|
||||
|
@ -208,7 +208,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"DUST",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x1f),
|
||||
"",
|
||||
{
|
||||
|
@ -228,7 +228,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"BATTERY_VOLTAGE",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x0f00),
|
||||
"",
|
||||
{
|
||||
|
@ -267,7 +267,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"OBSTACLE_DISTANCE",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x700000),
|
||||
"",
|
||||
{
|
||||
|
@ -297,7 +297,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"HEAD_STATUS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff8ff0e0),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffffffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -80,7 +80,7 @@ namespace
|
|||
"Current power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::PowerW)
|
||||
|
@ -91,7 +91,7 @@ namespace
|
|||
"Total volume of heat media.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -102,7 +102,7 @@ namespace
|
|||
"The total energy consumption recorded at the target date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -114,7 +114,7 @@ namespace
|
|||
"The flow temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -125,7 +125,7 @@ namespace
|
|||
"The return temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
|
@ -136,7 +136,7 @@ namespace
|
|||
"The external temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -147,7 +147,7 @@ namespace
|
|||
"How long the meter has been collecting data.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::OperatingTime)
|
||||
|
@ -167,7 +167,7 @@ namespace
|
|||
"Battery voltage.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -80,7 +80,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"",
|
||||
{
|
||||
|
@ -101,7 +101,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -112,7 +112,7 @@ namespace
|
|||
"Power measured by this meter at the moment.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::AutoSigned,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -123,7 +123,7 @@ namespace
|
|||
"The total energy backward (production) recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -135,7 +135,7 @@ namespace
|
|||
"The reactive total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Reactive_Energy,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FB8275"))
|
||||
);
|
||||
|
@ -145,7 +145,7 @@ namespace
|
|||
"The total reactive energy backward (production) recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Reactive_Energy,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(DifVifKey("04FB82F53C"))
|
||||
|
@ -177,7 +177,7 @@ namespace
|
|||
"Amperage at phase L1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDD9FC01"))
|
||||
);
|
||||
|
@ -187,7 +187,7 @@ namespace
|
|||
"Amperage at phase L2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDD9FC02"))
|
||||
);
|
||||
|
@ -197,7 +197,7 @@ namespace
|
|||
"Amperage at phase L3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDD9FC03"))
|
||||
);
|
||||
|
@ -207,7 +207,7 @@ namespace
|
|||
"Voltage at phase L1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDC8FC01"))
|
||||
);
|
||||
|
@ -217,7 +217,7 @@ namespace
|
|||
"Voltage at phase L2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDC8FC02"))
|
||||
);
|
||||
|
@ -227,7 +227,7 @@ namespace
|
|||
"Voltage at phase L3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDC8FC03"))
|
||||
);
|
||||
|
@ -237,7 +237,7 @@ namespace
|
|||
"Frequency in 0.1 Hz",
|
||||
DEFAULT_PRINT_PROPERTIES | PrintProperty::HIDE,
|
||||
Quantity::Frequency,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("02FB2E"))
|
||||
);
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -53,7 +53,7 @@ namespace
|
|||
"The target water consumption recorded at previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -56,7 +56,7 @@ namespace
|
|||
"The energy consumption recorded by this meter at the set date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -68,7 +68,7 @@ namespace
|
|||
"The active power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -79,7 +79,7 @@ namespace
|
|||
"The flow of water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -90,7 +90,7 @@ namespace
|
|||
"The maximum forward flow of water since the last set date?",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -101,7 +101,7 @@ namespace
|
|||
"The forward temperature of the water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -112,7 +112,7 @@ namespace
|
|||
"The return temperature of the water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
|
@ -123,7 +123,7 @@ namespace
|
|||
"The temperature difference forward-return for the water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::AutoSigned,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::TemperatureDifference)
|
||||
|
@ -134,7 +134,7 @@ namespace
|
|||
"The total amount of water that has passed through this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -145,7 +145,7 @@ namespace
|
|||
"The amount of water that had passed through this meter at the set date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -157,7 +157,7 @@ namespace
|
|||
"The amount of water that has passed through subunit 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -169,7 +169,7 @@ namespace
|
|||
"The amount of water that had passed through the subunit 1 at the set date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -182,7 +182,7 @@ namespace
|
|||
"The current heat cost allocation for subunit 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -194,7 +194,7 @@ namespace
|
|||
"The heat cost allocation for subunit 1 at the target date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -207,7 +207,7 @@ namespace
|
|||
"The current heat cost allocation for subunit 2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -219,7 +219,7 @@ namespace
|
|||
"The heat cost allocation for subunit 2 at the target date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -237,7 +237,7 @@ namespace
|
|||
.set(StorageNr(1))
|
||||
);
|
||||
|
||||
addOptionalCommonFields("operating_time_h,on_time_h,meter_datetime");
|
||||
addOptionalLibraryFields("operating_time_h,on_time_h,meter_datetime");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ namespace
|
|||
"The water consumption at the last billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -95,7 +95,7 @@ namespace
|
|||
info,
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("fabrication_no,enhanced_id,location");
|
||||
addOptionalLibraryFields("fabrication_no,enhanced_id,location");
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"location_hex",
|
||||
|
@ -53,7 +53,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -64,7 +64,7 @@ namespace
|
|||
"Calculated sum of power consumption of all phases.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
"The total energy production recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -87,7 +87,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter on tariff 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -99,7 +99,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter on tariff 2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -111,7 +111,7 @@ namespace
|
|||
"Current power consumption phase 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF01"))
|
||||
);
|
||||
|
@ -121,7 +121,7 @@ namespace
|
|||
"Current power consumption phase 2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF02"))
|
||||
);
|
||||
|
@ -131,7 +131,7 @@ namespace
|
|||
"Current power consumption phase 3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF03"))
|
||||
);
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -98,7 +98,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -109,7 +109,7 @@ namespace
|
|||
"The heat cost allocation at set date #.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -121,7 +121,7 @@ namespace
|
|||
"Deprecated field.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -53,7 +53,7 @@ namespace
|
|||
"The target water consumption recorded at previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace
|
|||
addStringFieldWithExtractorAndLookup(
|
||||
"current_status",
|
||||
"Status of meter.",
|
||||
DEFAULT_PRINT_PROPERTIES
|
||||
DEFAULT_PRINT_PROPERTIES
|
||||
| PrintProperty::STATUS | PrintProperty::INCLUDE_TPL_STATUS,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
|
@ -49,7 +49,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -59,15 +59,15 @@ namespace
|
|||
},
|
||||
});
|
||||
|
||||
addOptionalCommonFields("fabrication_no");
|
||||
addOptionalFlowRelatedFields("total_m3");
|
||||
addOptionalLibraryFields("fabrication_no");
|
||||
addOptionalLibraryFields("total_m3");
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"consumption_at_set_date",
|
||||
"The total water consumption at the most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -89,7 +89,7 @@ namespace
|
|||
"The total water consumption at the second most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -111,7 +111,7 @@ namespace
|
|||
"Maximum water flow since date time.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -133,7 +133,7 @@ namespace
|
|||
"The total water consumption at the historic date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -145,7 +145,7 @@ namespace
|
|||
"Reference date for history.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Date)
|
||||
|
|
|
@ -105,7 +105,7 @@ namespace
|
|||
leadingZeroString(month_prev) + "-" +
|
||||
leadingZeroString(day_prev) + "T02:00:00Z";
|
||||
|
||||
setStringValue("previous_date", previous_date);
|
||||
setStringValue("previous_date", previous_date, NULL);
|
||||
|
||||
string bytes = tostrprintf("%02x%02x", content[1], content[2]);
|
||||
string info = "*** "+bytes+" previous_date = %s";
|
||||
|
@ -147,7 +147,7 @@ namespace
|
|||
leadingZeroString(month_curr) + "-" +
|
||||
leadingZeroString(day_curr) + "T02:00:00Z";
|
||||
|
||||
setStringValue("current_date", current_date);
|
||||
setStringValue("current_date", current_date, NULL);
|
||||
|
||||
bytes = tostrprintf("%02x%02x", content[5], content[6]);
|
||||
info = "*** "+bytes+" current_date = %s";
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
);
|
||||
|
@ -69,7 +69,7 @@ namespace
|
|||
"Heat cost allocation at the most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(1))
|
||||
|
@ -89,7 +89,7 @@ namespace
|
|||
"Heat cost allocation at the most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(1))
|
||||
|
@ -109,7 +109,7 @@ namespace
|
|||
"Heat cost allocation at the 8 billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(8))
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffffffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -82,7 +82,7 @@ namespace
|
|||
"The total water consumption recorded at the beginning of this month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -104,7 +104,7 @@ namespace
|
|||
"The current flow of water through the meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -115,7 +115,7 @@ namespace
|
|||
"The water temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -127,7 +127,7 @@ namespace
|
|||
"The maximum water temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -139,7 +139,7 @@ namespace
|
|||
"The external temperature outside of the meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -151,7 +151,7 @@ namespace
|
|||
"The maximum flow recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -163,7 +163,7 @@ namespace
|
|||
"The minimum flow recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -175,7 +175,7 @@ namespace
|
|||
"The maximum temperature recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -187,7 +187,7 @@ namespace
|
|||
"The minimum flow recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -199,7 +199,7 @@ namespace
|
|||
"The maximum flow recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -216,7 +216,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"DRY",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x0070),
|
||||
"",
|
||||
{
|
||||
|
@ -243,7 +243,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"REVERSED",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x0380),
|
||||
"",
|
||||
{
|
||||
|
@ -270,7 +270,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"LEAKING",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x1c00),
|
||||
"",
|
||||
{
|
||||
|
@ -297,7 +297,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"BURSTING",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0xe000),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -70,10 +70,10 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger,
|
||||
AutoMask,
|
||||
"",
|
||||
"OK",
|
||||
{
|
||||
{ 0x0001, "METER_HARDWARE_ERROR" },
|
||||
{ 0x0002, "RTC_ERROR" },
|
||||
|
@ -85,10 +85,10 @@ namespace
|
|||
},
|
||||
{
|
||||
"ERROR_FLAGS_SINGLE_PHASE",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
TriggerBits(0x01020000),
|
||||
AutoMask,
|
||||
"",
|
||||
"OK",
|
||||
{
|
||||
{ 0x0008, "DEVICE_NOT_CONFIGURED" },
|
||||
{ 0x0010, "INTERNAL_ERROR" },
|
||||
|
@ -99,10 +99,10 @@ namespace
|
|||
},
|
||||
{
|
||||
"ERROR_FLAGS_THREE_PHASE",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
TriggerBits(0x01010000),
|
||||
AutoMask,
|
||||
"",
|
||||
"OK",
|
||||
{
|
||||
{ 0x0008, "CALIBRATION_EEPROM_ERROR" },
|
||||
{ 0x0010, "NETWORK_INTERFERENCE" },
|
||||
|
@ -124,7 +124,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"INFO_FLAGS",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger,
|
||||
AutoMask,
|
||||
"",
|
||||
|
@ -141,7 +141,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -152,7 +152,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -164,7 +164,7 @@ namespace
|
|||
"Last day?",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
|
@ -176,7 +176,7 @@ namespace
|
|||
"Last day energy consumption?",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -188,7 +188,7 @@ namespace
|
|||
"Last day energy consumption for tariff?",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -201,7 +201,7 @@ namespace
|
|||
"Device date time when telegram was sent.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
|
@ -212,7 +212,7 @@ namespace
|
|||
"Voltage for single phase meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -224,7 +224,7 @@ namespace
|
|||
"Voltage at phase L#.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -236,7 +236,7 @@ namespace
|
|||
"Amperage for single phase meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Amperage)
|
||||
|
@ -248,7 +248,7 @@ namespace
|
|||
"Amperage at phase L#.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Amperage)
|
||||
|
@ -260,7 +260,7 @@ namespace
|
|||
"Raw input to frequency.",
|
||||
DEFAULT_PRINT_PROPERTIES | PrintProperty::HIDE,
|
||||
Quantity::Frequency,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("02FB2D"))
|
||||
);
|
||||
|
|
|
@ -38,8 +38,8 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("actuality_duration_s");
|
||||
addOptionalFlowRelatedFields("total_m3,target_m3,target_date");
|
||||
addOptionalLibraryFields("actuality_duration_s");
|
||||
addOptionalLibraryFields("total_m3,target_m3,target_date");
|
||||
|
||||
addStringField(
|
||||
"status",
|
||||
|
@ -77,7 +77,7 @@ namespace
|
|||
|
||||
if (type != 1)
|
||||
{
|
||||
setStringValue("mfct_status", tostrprintf("UKNOWN_MFCT_STATUS=%02x%02x%02x", type, a, b));
|
||||
setStringValue("mfct_status", tostrprintf("UKNOWN_MFCT_STATUS=%02x%02x%02x", type, a, b), NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -89,9 +89,9 @@ namespace
|
|||
if (a & 0x40) info += "BACKFLOW ";
|
||||
|
||||
if (info.size() > 0) info.pop_back();
|
||||
setStringValue("mfct_status", info);
|
||||
setStringValue("mfct_status", info, NULL);
|
||||
|
||||
setStringValue("power_mode", (b & 0x01) ? "SAVING" : "NORMAL");
|
||||
setStringValue("power_mode", (b & 0x01) ? "SAVING" : "NORMAL", NULL);
|
||||
|
||||
double battery_semesters = (b >> 3); // Half years.
|
||||
setNumericValue("battery", Unit::Year, battery_semesters/2.0);
|
||||
|
@ -100,5 +100,5 @@ namespace
|
|||
|
||||
// Test: Wateroo gwfwater 20221031 NOKEY
|
||||
// telegram=|3144E61E31102220010E8C04F47ABE0420452F2F_037410000004133E0000004413FFFFFFFF426CFFFF0F0120012F2F2F2F2F|
|
||||
// {"actuality_duration_s": 16,"battery_y": 0,"id": "20221031","media": "bus/system component","meter": "gwfwater","name": "Wateroo","power_mode": "SAVING","status": "BATTERY_LOW POWER_LOW","target_date": "2128-03-31","target_m3": 4294967.295,"timestamp": "1111-11-11T11:11:11Z","total_m3": 0.062}
|
||||
// {"actuality_duration_s": 16,"battery_y": 0,"id": "20221031","media": "bus/system component","meter": "gwfwater","name": "Wateroo","power_mode": "SAVING","status": "BATTERY_LOW POWER_LOW","target_date": "2128-03-31","target_m3": -0.001,"timestamp": "1111-11-11T11:11:11Z","total_m3": 0.062}
|
||||
// |Wateroo;20221031;0.062;1111-11-11 11:11.11
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -80,7 +80,7 @@ namespace
|
|||
"The heat cost allocation at set date #.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -92,7 +92,7 @@ namespace
|
|||
"Deprecated field.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace
|
|||
{
|
||||
setMfctTPLStatusBits(
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xe0))
|
||||
.set(DefaultMessage("OK"))
|
||||
.add(Translate::Map(0x80 ,"SABOTAGE_ENCLOSURE", TestBit::Set))));
|
||||
|
@ -55,7 +55,7 @@ namespace
|
|||
"The total heating energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -67,7 +67,7 @@ namespace
|
|||
"The date time when the recording was made.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
|
@ -78,7 +78,7 @@ namespace
|
|||
"The total cooling energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -90,7 +90,7 @@ namespace
|
|||
"Total heating volume of media.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -102,7 +102,7 @@ namespace
|
|||
"Total cooling volume of media.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -114,7 +114,7 @@ namespace
|
|||
"Supply c1 volume.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -126,7 +126,7 @@ namespace
|
|||
"Return c2 volume.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -138,7 +138,7 @@ namespace
|
|||
"The supply t1 pipe temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -150,7 +150,7 @@ namespace
|
|||
"The return t2 pipe temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2019-2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
Copyright (C) 2019-2023 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -31,6 +31,7 @@ namespace
|
|||
di.setMeterType(MeterType::WaterMeter);
|
||||
di.addLinkMode(LinkMode::T1);
|
||||
di.addDetection(MANUFACTURER_BMT, 0x06, 0x13);
|
||||
di.addDetection(MANUFACTURER_BMT, 0x06, 0x17);
|
||||
di.addDetection(MANUFACTURER_BMT, 0x07, 0x13);
|
||||
di.addDetection(MANUFACTURER_BMT, 0x07, 0x15);
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
|
@ -43,7 +44,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -54,7 +55,7 @@ namespace
|
|||
"Meter timestamp for measurement.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime),
|
||||
|
@ -67,3 +68,8 @@ namespace
|
|||
// telegram=|4E44B4098686868613077AF0004005_2F2F0C1366380000046D27287E2A0F150E00000000C10000D10000E60000FD00000C01002F0100410100540100680100890000A00000B30000002F2F2F2F2F2F|
|
||||
// {"media":"water","meter":"hydrodigit","name":"HydrodigitWater","id":"86868686","total_m3":3.866,"meter_datetime":"2019-10-30 08:39","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |HydrodigitWater;86868686;3.866;2019-10-30 08:39;1111-11-11 11:11.11
|
||||
|
||||
// Test: HydridigitWaterr hydrodigit 03245501 NOKEY
|
||||
// telegram=|2444B4090155240317068C00487AC0000000_0C1335670000046D172EEA280F030000000000|
|
||||
// {"id": "03245501","media": "warm water","meter": "hydrodigit","meter_datetime": "2023-08-10 14:23","name": "HydridigitWaterr","timestamp": "1111-11-11T11:11:11Z","total_m3": 6.735}
|
||||
// |HydridigitWaterr;03245501;6.735;2023-08-10 14:23;1111-11-11 11:11.11
|
||||
|
|
|
@ -44,8 +44,8 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("operating_time_h,actuality_duration_s,meter_datetime,customer");
|
||||
addOptionalFlowRelatedFields("flow_temperature_c,external_temperature_c");
|
||||
addOptionalLibraryFields("operating_time_h,actuality_duration_s,meter_datetime,customer");
|
||||
addOptionalLibraryFields("flow_temperature_c,external_temperature_c");
|
||||
|
||||
addStringField(
|
||||
"status",
|
||||
|
@ -57,7 +57,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -68,7 +68,7 @@ namespace
|
|||
"The total water consumption recorded on tariff # by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -80,7 +80,7 @@ namespace
|
|||
"The total water consumption recorded on tariff # by this meter at billing date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -93,7 +93,7 @@ namespace
|
|||
"The current water flow.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow));
|
||||
|
@ -103,7 +103,7 @@ namespace
|
|||
"The total water consumption recorded at date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -115,7 +115,7 @@ namespace
|
|||
"The last billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Date)
|
||||
|
@ -124,11 +124,11 @@ namespace
|
|||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"total_at_date",
|
||||
"Fix this! The total water consumption recorded at last day. Perhaps?",
|
||||
"target",
|
||||
"The total water consumption recorded at the end of last month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -136,11 +136,11 @@ namespace
|
|||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"at",
|
||||
"Fix this! The last billing period date last day. Perhaps?",
|
||||
"target",
|
||||
"The end of last month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
|
@ -152,7 +152,7 @@ namespace
|
|||
"Remaining battery life in years.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::RemainingBattery),
|
||||
|
@ -163,14 +163,14 @@ namespace
|
|||
// Test: HydrusWater hydrus 64646464 NOKEY
|
||||
// Comment:
|
||||
// telegram=|4E44A5116464646470077AED004005_2F2F01FD08300C13741100007C1300000000FC101300000000FC201300000000726C00000B3B00000002FD748713025A6800C4016D3B177F2ACC011300020000|
|
||||
// {"media":"water","meter":"hydrus","name":"HydrusWater","id":"64646464","total_m3":1.174,"flow_m3h":0,"flow_temperature_c":10.4,"remaining_battery_life_y":13.686797,"status":"OK","at_datetime":"2019-10-31 23:59","total_at_date_m3": 0.2,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |HydrusWater;64646464;1.174;0.2;OK;1111-11-11 11:11.11
|
||||
// {"media":"water","meter":"hydrus","name":"HydrusWater","id":"64646464","total_m3":1.174,"flow_m3h":0,"flow_temperature_c":10.4,"remaining_battery_life_y":13.686797,"status":"OK","target_datetime":"2019-10-31 23:59","target_m3": 0.2,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |HydrusWater;64646464;1.174;null;OK;1111-11-11 11:11.11
|
||||
|
||||
// Test: HydrusVater hydrus 65656565 NOKEY
|
||||
// Comment:
|
||||
// telegram=|3E44A5116565656570067AFB0030052F2F_0C13503400000DFD110A383731303134423032410B3B00000002FD74DC15C4016D3B178D29CC0113313400002F2F|
|
||||
// {"media":"warm water","meter":"hydrus","name":"HydrusVater","id":"65656565","flow_m3h":0,"customer": "A20B410178","total_m3":3.45,"total_at_date_m3":3.431,"remaining_battery_life_y":15.321328,"at_datetime":"2020-09-13 23:59","total_at_date_m3": 3.431,"status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |HydrusVater;65656565;3.45;3.431;OK;1111-11-11 11:11.11
|
||||
// {"media":"warm water","meter":"hydrus","name":"HydrusVater","id":"65656565","flow_m3h":0,"customer": "A20B410178","total_m3":3.45,"remaining_battery_life_y":15.321328,"target_datetime":"2020-09-13 23:59","target_m3": 3.431,"status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |HydrusVater;65656565;3.45;null;OK;1111-11-11 11:11.11
|
||||
|
||||
// Test: HydrusAES hydrus 64745666 NOKEY
|
||||
// Comment:
|
||||
|
@ -189,3 +189,9 @@ namespace
|
|||
// telegram=|1E4424238B06204790607A2A0010D8_0413DDC00000426CBF23441382BB0000|
|
||||
// {"media":"warm water","meter":"hydrus","name":"HydrusIzarRSWarm","id":"60904720","total_m3":49.373,"total_at_date_m3":48.002,"at_date":"2021-03-31","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |HydrusIzarRSWarm;60904720;49.373;48.002;OK;1111-11-11 11:11.11
|
||||
|
||||
// Test: HydrusFoo hydrus 64641820 NOKEY
|
||||
// Comment: Negative power values.
|
||||
// telegram=|6344A5112018646470078C00D7900F002C256AB59B00F0F13032019092DE7A6A004007102F2F0C13896729004C1323462400CC101300000000CC201323462400426CDF2C0B3B0200F002FD742F0D025AC100C4016D3B17FE29CC01132841290001FD089F|
|
||||
// {"at_date": "2022-12-31","target_datetime": "2023-09-30 23:59","flow_m3h": -0.002,"flow_temperature_c": 19.3,"id": "64641820","media": "water","meter": "hydrus","name": "HydrusFoo","remaining_battery_life_y": 9.240436,"status": "OK","timestamp": "1111-11-11T11:11:11Z","total_at_date_m3":244.623,"target_m3": 294.128,"total_m3": 296.789,"total_tariff1_at_date_m3": 0,"total_tariff2_at_date_m3": 244.623}
|
||||
// |HydrusFoo;64641820;296.789;244.623;OK;1111-11-11 11:11.11
|
||||
|
|
Plik diff jest za duży
Load Diff
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
Copyright (C) 2018 David Mallon (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include"meters_common_implementation.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Driver : public virtual MeterCommonImplementation
|
||||
{
|
||||
Driver(MeterInfo &mi, DriverInfo &di);
|
||||
};
|
||||
|
||||
static bool ok = registerDriver([](DriverInfo&di)
|
||||
{
|
||||
di.setName("iperl");
|
||||
di.setDefaultFields("name,id,total_m3,max_flow_m3h,timestamp");
|
||||
di.setMeterType(MeterType::WaterMeter);
|
||||
di.addLinkMode(LinkMode::T1);
|
||||
di.addDetection(MANUFACTURER_SEN, 0x06, 0x68);
|
||||
di.addDetection(MANUFACTURER_SEN, 0x07, 0x68);
|
||||
di.addDetection(MANUFACTURER_SEN, 0x07, 0x7c);
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
});
|
||||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addNumericFieldWithExtractor(
|
||||
"total",
|
||||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"max_flow",
|
||||
"The maximum flow recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow));
|
||||
}
|
||||
}
|
||||
|
||||
// Test: MoreWater iperl 12345699 NOKEY
|
||||
// Comment: Test iPerl T1 telegram, that after decryption, has 2f2f markers.
|
||||
// telegram=|1E44AE4C9956341268077A36001000_2F2F0413181E0000023B00002F2F2F2F|
|
||||
// {"media":"water","meter":"iperl","name":"MoreWater","id":"12345699","total_m3":7.704,"max_flow_m3h":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |MoreWater;12345699;7.704;0;1111-11-11 11:11.11
|
||||
|
||||
// Test: WaterWater iperl 33225544 NOKEY
|
||||
// Comment: Test iPerl T1 telegram not encrypted, which has no 2f2f markers.
|
||||
// telegram=|1844AE4C4455223368077A55000000_041389E20100023B0000|
|
||||
// {"media":"water","meter":"iperl","name":"WaterWater","id":"33225544","total_m3":123.529,"max_flow_m3h":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |WaterWater;33225544;123.529;0;1111-11-11 11:11.11
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
Copyright (C) 2022-2023 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -30,8 +30,10 @@ namespace
|
|||
di.setDefaultFields("name,id,total_m3,target_m3,timestamp");
|
||||
di.setMeterType(MeterType::WaterMeter);
|
||||
di.addLinkMode(LinkMode::T1);
|
||||
di.addDetection(MANUFACTURER_ITW, 0x07, 0x00);
|
||||
di.addDetection(MANUFACTURER_ITW, 0x07, 0x03);
|
||||
di.addDetection(MANUFACTURER_ITW, 0x07, 0x33);
|
||||
di.addDetection(MANUFACTURER_ITW, 0x16, 0x00);
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
});
|
||||
|
||||
|
@ -43,8 +45,8 @@ namespace
|
|||
|
||||
addLinkMode(LinkMode::T1);
|
||||
|
||||
addOptionalCommonFields("enhanced_id,meter_datetime");
|
||||
addOptionalFlowRelatedFields("total_m3,total_backward_m3,volume_flow_m3h");
|
||||
addOptionalLibraryFields("enhanced_id,meter_datetime");
|
||||
addOptionalLibraryFields("total_m3,total_backward_m3,volume_flow_m3h");
|
||||
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
"status",
|
||||
|
@ -58,7 +60,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -73,7 +75,7 @@ namespace
|
|||
"The total water consumption recorded at the end of previous billing period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -100,7 +102,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"WOOTA",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffffffff),
|
||||
"",
|
||||
{
|
||||
|
@ -120,7 +122,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"WOOTB",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"",
|
||||
{
|
||||
|
@ -143,3 +145,14 @@ namespace
|
|||
// telegram=|46449726560000183307725600001897263307AF0030052F2F_066D0E1015C82A000C13771252000C933C000000000B3B0400004C1361045200426CC12A03FD971C0000002F2F2F|
|
||||
// {"media":"water","meter":"itron","name":"MoreWater","id":"18000056","meter_datetime":"2022-10-08 21:16:14","total_m3":521.277,"total_backward_m3":0,"volume_flow_m3h":0.004,"status":"OK","target_m3":520.461,"target_date":"2022-10-01","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |MoreWater;18000056;521.277;520.461;1111-11-11 11:11.11
|
||||
|
||||
// Test: AnyWater itron 20310959 NOKEY
|
||||
// telegram=|384497265909312000077a930000a0041360B50100066d101295f427004413ac570100426cdf2c047f0000060c027f6c2a0e79000000000000|
|
||||
// {"enhanced_id": "000000000000","id": "20310959","media": "water","meter": "itron","meter_datetime": "2023-07-20 21:18:16","name": "AnyWater","status": "OK","target_date": "2022-12-31","target_m3": 87.98,"timestamp": "1111-11-11T11:11:11Z","total_m3": 111.968,"unknown_a": "WOOTA_C060000","unknown_b": "WOOTB_2A6C"}
|
||||
// |AnyWater;20310959;111.968;87.98;1111-11-11 11:11.11
|
||||
|
||||
// Test: ColdWaterMeter itron 23362098 NOKEY
|
||||
// Comment: Allmess cold water with Itron Module programmed with type 0x16
|
||||
// telegram=|3A4497269820362300167AF60020A52F2F_04132E100000066D03260DE12B007413FEFEFEFE426C1F01047F1600060C027F9A2A0E79187103002300|
|
||||
// {"enhanced_id": "002300037118", "id": "23362098", "media": "cold water", "meter": "itron", "meter_datetime": "2023-11-01 13:38:03", "name": "ColdWaterMeter", "status": "OK", "target_date": "2000-01-31", "timestamp": "1111-11-11T11:11:11Z", "total_m3": 4.142,"unknown_a": "WOOTA_C060016","unknown_b": "WOOTB_2A9A" }
|
||||
// |ColdWaterMeter;23362098;4.142;null;1111-11-11 11:11.11
|
||||
|
|
|
@ -29,16 +29,17 @@ namespace
|
|||
di.setName("iwmtx5");
|
||||
di.setDefaultFields("name,id,status,total_m3,timestamp");
|
||||
|
||||
di.setMeterType(MeterType::HeatMeter);
|
||||
di.setMeterType(MeterType::WaterMeter);
|
||||
di.addLinkMode(LinkMode::T1);
|
||||
di.addDetection(MANUFACTURER_BMT, 0x07, 0x18);
|
||||
di.addDetection(MANUFACTURER_BMT, 0x06, 0x18);
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
});
|
||||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("meter_datetime");
|
||||
addOptionalFlowRelatedFields("total_m3");
|
||||
addOptionalLibraryFields("meter_datetime");
|
||||
addOptionalLibraryFields("total_m3");
|
||||
|
||||
addStringField(
|
||||
"status",
|
||||
|
@ -51,3 +52,8 @@ namespace
|
|||
// telegram=|5144b4097073912218078c00247a0308400571e9615249ede52eaae09f61908f027c3877f3330ae9079528b23173ce124bcc255393e60b173c0a9f274c42dd92e4b23c14e8a41f042903358df01dd9268ad4|
|
||||
// {"id": "22917370","media": "water","meter": "iwmtx5","meter_datetime": "2023-05-11 10:38:24","name": "WaterWater","status": "PERMANENT_ERROR","timestamp": "1111-11-11T11:11:11Z","total_m3": 0.025}
|
||||
// |WaterWater;22917370;PERMANENT_ERROR;0.025;1111-11-11 11:11.11
|
||||
|
||||
// Test: WarmWater2 iwmtx5 23329344 NOKEY
|
||||
// telegram=|4244B4094493322318068C005B7A1C0000000C13072000000F05170000000000000000000000000000000000000000009D0000C20000C20000C8000000000000000000|
|
||||
// {"id": "23329344","media": "warm water","meter": "iwmtx5","name": "WarmWater2","status": "OK","timestamp": "1111-11-11T11:11:11Z","total_m3": 2.007}
|
||||
// |WarmWater2;23329344;OK;2.007;1111-11-11 11:11.11
|
||||
|
|
|
@ -214,11 +214,11 @@ namespace
|
|||
// get the manufacture year
|
||||
uint8_t yy = atoi(digits.substr(0, 2).c_str());
|
||||
int manufacture_year = yy > 70 ? (1900 + yy) : (2000 + yy); // Maybe to adjust in 2070, if this code stills lives :D
|
||||
setStringValue("manufacture_year", tostrprintf("%d", manufacture_year));
|
||||
setStringValue("manufacture_year", tostrprintf("%d", manufacture_year), NULL);
|
||||
|
||||
// get the serial number
|
||||
uint32_t serial_number = atoi(digits.substr(2, digits.size()).c_str());
|
||||
setStringValue("serial_number", tostrprintf("%06d", serial_number));
|
||||
setStringValue("serial_number", tostrprintf("%06d", serial_number), NULL);
|
||||
|
||||
// get letters
|
||||
uchar supplier_code = '@' + (((origin[9] & 0x0F) << 1) | (origin[8] >> 7));
|
||||
|
@ -226,7 +226,7 @@ namespace
|
|||
uchar diameter = '@' + (((origin[8] & 0x03) << 3) | (origin[7] >> 5));
|
||||
// build the prefix
|
||||
string prefix = tostrprintf("%c%02d%c%c", supplier_code, yy, meter_type, diameter);
|
||||
setStringValue("prefix", prefix);
|
||||
setStringValue("prefix", prefix, NULL);
|
||||
}
|
||||
|
||||
// get the remaining battery life (in year) and transmission period (in seconds)
|
||||
|
@ -252,7 +252,7 @@ namespace
|
|||
uint8_t h0_month = decoded_content[10] & 0xF;
|
||||
uint8_t h0_day = decoded_content[9] & 0x1F;
|
||||
|
||||
setStringValue("last_month_measure_date", tostrprintf("%d-%02d-%02d", h0_year, h0_month%99, h0_day%99));
|
||||
setStringValue("last_month_measure_date", tostrprintf("%d-%02d-%02d", h0_year, h0_month%99, h0_day%99), NULL);
|
||||
|
||||
// read the alarms:
|
||||
IzarAlarms alarms {};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2018-2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
Copyright (C) 2018-2024 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
Copyright (C) 2020 Eric Bus (gpl-3.0-or-later)
|
||||
Copyright (C) 2022 thecem (gpl-3.0-or-later)
|
||||
|
||||
|
@ -43,14 +43,15 @@ namespace
|
|||
di.addDetection(MANUFACTURER_KAM, 0x0c, 0x30); // 302
|
||||
di.addDetection(MANUFACTURER_KAM, 0x04, 0x40); // 303
|
||||
di.addDetection(MANUFACTURER_KAM, 0x0c, 0x40); // 303
|
||||
di.addDetection(MANUFACTURER_KAM, 0x04, 0x19); // 402
|
||||
di.addDetection(MANUFACTURER_KAM, 0x04, 0x34); // 403
|
||||
di.addDetection(MANUFACTURER_KAM, 0x0a, 0x34); // 403
|
||||
di.addDetection(MANUFACTURER_KAM, 0x0b, 0x34); // 403
|
||||
di.addDetection(MANUFACTURER_KAM, 0x0c, 0x34); // 403
|
||||
di.addDetection(MANUFACTURER_KAM, 0x0d, 0x34); // 403
|
||||
di.addDetection(MANUFACTURER_KAM, 0x04, 0x1c); // 602
|
||||
di.addDetection(MANUFACTURER_KAM, 0x04, 0x35); // 603
|
||||
di.addDetection(MANUFACTURER_KAM, 0x0c, 0x35); // 603
|
||||
di.addDetection(MANUFACTURER_KAM, 0x04, 0x35); // 603
|
||||
di.addDetection(MANUFACTURER_KAM, 0x0c, 0x35); // 603
|
||||
di.addDetection(MANUFACTURER_KAM, 0x04, 0x39); // 803
|
||||
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
|
@ -58,7 +59,8 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("on_time_h");
|
||||
addOptionalLibraryFields("fabrication_no,meter_datetime,on_time_h,on_time_at_error_h");
|
||||
addOptionalLibraryFields("flow_return_temperature_difference_c");
|
||||
|
||||
// Technical Description Multical 603 page 116 section 7.7.2 Information code types on serial communication.
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
|
@ -72,7 +74,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffffffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -118,7 +120,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -129,7 +131,7 @@ namespace
|
|||
"The volume of water (3/68/Volume V1).",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -140,7 +142,7 @@ namespace
|
|||
"The actual amount of water that pass through this meter (8/74/Flow V1 actual).",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -151,7 +153,7 @@ namespace
|
|||
"The current power flowing.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -162,7 +164,7 @@ namespace
|
|||
"The maximum power supplied.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -173,7 +175,7 @@ namespace
|
|||
"The forward temperature of the water (6/86/t2 actual 2 decimals).",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -184,7 +186,7 @@ namespace
|
|||
"The return temperature of the water (7/87/t2 actual 2 decimals).",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
|
@ -195,7 +197,7 @@ namespace
|
|||
"The maximum flow of water that passed through this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -206,7 +208,7 @@ namespace
|
|||
"The forward energy of the water (4/97/Energy E8).",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FF07")),
|
||||
Unit::M3C);
|
||||
|
@ -216,7 +218,7 @@ namespace
|
|||
"The return energy of the water (5/110/Energy E9).",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FF08")),
|
||||
Unit::M3C);
|
||||
|
@ -235,7 +237,7 @@ namespace
|
|||
"The energy consumption recorded by this meter at the set date (11/60/Heat energy E1/026C).",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -247,7 +249,7 @@ namespace
|
|||
"The amount of water that had passed through this meter at the set date (13/68/Volume V1).",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -269,7 +271,7 @@ namespace
|
|||
"How long the meter has been collecting data.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::OperatingTime)
|
||||
|
@ -312,11 +314,11 @@ namespace
|
|||
|
||||
// Test: My403Cooling multical403 78780102 NOKEY
|
||||
// telegram=|88442D2C02017878340A8D208D529C132037FC78_040E2D0A000004FF07F8FF000004FF08401801000413C1900500844014000000008480401400000000043BED0000000259BC06025DCD07142DE7FFFFFF84100E0000000084200E0000000004FF2200000000026C9228440E5F0300004413960D0200C4401400000000C480401400000000426C8128|
|
||||
// {"forward_energy_m3c": 65528,"id": "78780102","max_power_kw": 429496727.1,"media": "cooling load volume at outlet","meter": "kamheat","meter_date": "2020-08-18","name": "My403Cooling","return_energy_m3c": 71744,"status": "OK","t1_temperature_c": 17.24,"t2_temperature_c": 19.97,"target_date": "2020-08-01","target_energy_kwh": 239.722222,"target_volume_m3": 134.55,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 723.611111,"total_volume_m3": 364.737,"volume_flow_m3h": 0.237}
|
||||
// {"forward_energy_m3c": 65528,"id": "78780102","max_power_kw": -2.5,"media": "cooling load volume at outlet","meter": "kamheat","meter_date": "2020-08-18","name": "My403Cooling","return_energy_m3c": 71744,"status": "OK","t1_temperature_c": 17.24,"t2_temperature_c": 19.97,"target_date": "2020-08-01","target_energy_kwh": 239.722222,"target_volume_m3": 134.55,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 723.611111,"total_volume_m3": 364.737,"volume_flow_m3h": 0.237}
|
||||
// |My403Cooling;78780102;723.611111;364.737;OK;1111-11-11 11:11.11
|
||||
|
||||
// telegram=|5B442D2C02017878340A8D2096809C1320EF2B7934147ED7_2D0A0000FAFF000043180100CE9005000000000000000000EE000000BA06CB07E7FFFFFF00000000000000000000000092285F030000960D020000000000000000008128|
|
||||
// {"forward_energy_m3c": 65530,"id": "78780102","max_power_kw": 429496727.1,"media": "cooling load volume at outlet","meter": "kamheat","meter_date": "2020-08-18","name": "My403Cooling","return_energy_m3c": 71747,"status": "OK","t1_temperature_c": 17.22,"t2_temperature_c": 19.95,"target_date": "2020-08-01","target_energy_kwh": 239.722222,"target_volume_m3": 134.55,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 723.611111,"total_volume_m3": 364.75,"volume_flow_m3h": 0.238}
|
||||
// {"forward_energy_m3c": 65530,"id": "78780102","max_power_kw": -2.5,"media": "cooling load volume at outlet","meter": "kamheat","meter_date": "2020-08-18","name": "My403Cooling","return_energy_m3c": 71747,"status": "OK","t1_temperature_c": 17.22,"t2_temperature_c": 19.95,"target_date": "2020-08-01","target_energy_kwh": 239.722222,"target_volume_m3": 134.55,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 723.611111,"total_volume_m3": 364.75,"volume_flow_m3h": 0.238}
|
||||
// |My403Cooling;78780102;723.611111;364.75;OK;1111-11-11 11:11.11
|
||||
|
||||
// Test: Heato multical602 78152801 NOKEY
|
||||
|
@ -342,3 +344,18 @@ namespace
|
|||
// telegram=|68464668084a72447744772d2c3404060000000406ce86000004ff073444020004ff08f8ce0100041411680300043B0f02000002593c19025da41104ff220000000004a5ff21c7d02700d916|
|
||||
// {"forward_energy_m3c": 148532,"id": "77447744","media": "heat","meter": "kamheat","name": "Kamstrup_403_mbus","return_energy_m3c": 118520,"status": "OK","t1_temperature_c": 64.6,"t2_temperature_c": 45.16,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 34510,"total_volume_m3": 2232.49,"volume_flow_m3h": 0.527,"operating_time_h": 43489.183333}
|
||||
// |Kamstrup_403_mbus;77447744;34510;2232.49;OK;1111-11-11 11:11.11
|
||||
|
||||
// Test: Kamstrup_402_wmbus kamheat 62215006 NOKEY
|
||||
// telegram=|40442D2C0650216219048D2083A4E1162306FF78_040F2C3F000004FF07DBA40D0004FF08860B0D000414BA33140002FD170000043B620000000259A21E025DFA1B|
|
||||
// {"media":"heat","meter":"kamheat","name":"Kamstrup_402_wmbus","id":"62215006","forward_energy_m3c":894171,"return_energy_m3c":854918,"t1_temperature_c":78.42,"t2_temperature_c":71.62,"total_energy_consumption_kwh":44922.222222,"total_volume_m3":13239.62,"volume_flow_m3h":0.098,"status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Kamstrup_402_wmbus;62215006;44922.222222;13239.62;OK;1111-11-11 11:11.11
|
||||
|
||||
// Test: Kamstrup_MC603_mbus kamheat 32323232 NOKEY
|
||||
// telegram=|68c9c96808e672323232322d2c35041900000004fB006083000004ff074006010004ff08299400000416984e010084401400000000848040140000000004225043000034221c0000000259c91f025d4f1102617a0e042e30020000142e65030000043c24050000143ce308000004ff2200000000046d2e2B0f3144fB00007d000044ff07Bdf9000044ff08308d00004416B73f0100c4401400000000c480401400000000542ed9020000543ce8090000426c013102ff1a011B0c783032858404ff16e5841e0004ff17c1d5B400a516|
|
||||
// {"fabrication_no": "84853230", "flow_return_temperature_difference_c": 37.06, "forward_energy_m3c": 67136, "id": "32323232", "max_flow_m3h": 22.75, "max_power_kw": 869, "media": "heat", "meter": "kamheat", "meter_datetime": "2024-01-15 11:46", "name": "Kamstrup_MC603_mbus", "on_time_at_error_h": 28, "on_time_h": 17232, "power_kw": 560, "return_energy_m3c": 37929, "status": "OK", "t1_temperature_c": 81.37, "t2_temperature_c": 44.31, "target_date": "2024-01-01", "target_energy_kwh": 3200000, "target_volume_m3": 81847, "timestamp": "1111-11-11T11:11:11Z", "total_energy_consumption_kwh": 3363200, "total_volume_m3": 85656, "volume_flow_m3h": 13.16}
|
||||
// |Kamstrup_MC603_mbus;32323232;3363200;85656;OK;1111-11-11 11:11.11
|
||||
|
||||
// Test: KMHEAT kamheat 85412440 NOKEY
|
||||
// telegram=|5e442d2c4024418535047ae10050252f2f04fB091300000004167500000004ff2200000000043ca301000002599c1d025dB00e844014000000008480401400000000042eB9000000026c0534426c013444fB0900000000543c000000002f2f|
|
||||
// {"id": "85412440","media": "heat","meter": "kamheat","meter_date": "2024-04-05","name": "KMHEAT","power_kw": 185,"status": "OK","t1_temperature_c": 75.8,"t2_temperature_c": 37.6,"target_date": "2024-04-01","target_energy_kwh": 0,"timestamp": "1111-11-11T11:11:11Z","total_energy_consumption_kwh": 5277.777778,"total_volume_m3": 117,"volume_flow_m3h": 4.19}
|
||||
// |KMHEAT;85412440;5277.777778;117;OK;1111-11-11 11:11.11
|
||||
|
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include"meters_common_implementation.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Driver : public virtual MeterCommonImplementation
|
||||
{
|
||||
Driver(MeterInfo &mi, DriverInfo &di);
|
||||
};
|
||||
|
||||
static bool ok = registerDriver([](DriverInfo&di)
|
||||
{
|
||||
di.setName("kampress");
|
||||
di.setDefaultFields("name,id,status,pressure_bar,max_pressure_bar,min_pressure_bar,timestamp");
|
||||
di.setMeterType(MeterType::PressureSensor);
|
||||
di.addLinkMode(LinkMode::C1);
|
||||
di.addDetection(MANUFACTURER_KAM, 0x18, 0x01);
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
});
|
||||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
"status",
|
||||
"Status and error flags.",
|
||||
DEFAULT_PRINT_PROPERTIES | INCLUDE_TPL_STATUS,
|
||||
FieldMatcher::build()
|
||||
.set(VIFRange::ErrorFlags),
|
||||
{
|
||||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
{ 0x01, "DROP" }, // Unexpected drop in pressure in relation to average pressure.
|
||||
{ 0x02, "SURGE" }, // Unexpected increase in pressure in relation to average pressure.
|
||||
{ 0x04, "HIGH" }, // Average pressure has reached configurable limit. Default 15 bar
|
||||
{ 0x08, "LOW" }, // Average pressure has reached configurable limit. Default 1.5 bar
|
||||
{ 0x10, "TRANSIENT" }, // Pressure changes quickly over short timeperiods. Average is fluctuating.
|
||||
{ 0x20, "COMM_ERROR" } // Cannot measure properly or bad internal communication.
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"pressure",
|
||||
"The measured pressure.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Pressure,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Pressure)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"max_pressure",
|
||||
"The maximum pressure measured during ?.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Pressure,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::Pressure)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"min_pressure",
|
||||
"The minimum pressure measured during ?.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Pressure,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::Pressure)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"alfa",
|
||||
"We do not know what this is.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("05FF09"))
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"beta",
|
||||
"We do not know what this is.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("05FF0A"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Test: Pressing kampress 77000317 NOKEY
|
||||
// telegram=|32442D2C1703007701188D280080E39322DB8F78_22696600126967000269660005FF091954A33A05FF0A99BD823A02FD170800|
|
||||
// {"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.03,"min_pressure_bar":1.02,"alfa_counter":0.001246,"beta_counter":0.000997,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Pressing;77000317;LOW;1.02;1.03;1.02;1111-11-11 11:11.11
|
||||
|
||||
// telegram=|27442D2C1703007701188D280194E393226EC679DE735657_660067006600962B913A21B9423A0800|
|
||||
// {"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.03,"min_pressure_bar":1.02,"alfa_counter":0.001108,"beta_counter":0.000743,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Pressing;77000317;LOW;1.02;1.03;1.02;1111-11-11 11:11.11
|
||||
|
||||
// telegram=|27442D2C1703007701188D289554F295224ED579DE73188A_650066006600E80EA43A6B97A3BA0800|
|
||||
// {"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.02,"min_pressure_bar":1.01,"alfa_counter":0.001252,"beta_counter":-0.001248,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Pressing;77000317;LOW;1.02;1.02;1.01;1111-11-11 11:11.11
|
|
@ -44,7 +44,7 @@ namespace
|
|||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DigitalInput),
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("INPUT_BITS", Translate::Type::IndexToString)
|
||||
.add(Translate::Rule("INPUT_BITS", Translate::MapType::IndexToString)
|
||||
.set(MaskBits(0xffff))
|
||||
.add(Translate::Map(0x11 ,"CLOSED", TestBit::Set))
|
||||
.add(Translate::Map(0x55 ,"OPEN", TestBit::Set))
|
||||
|
@ -58,7 +58,7 @@ namespace
|
|||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ErrorFlags),
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xffff))
|
||||
.set(DefaultMessage("OK"))
|
||||
));
|
||||
|
@ -68,7 +68,7 @@ namespace
|
|||
"How many times the door/window has been opened or closed.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
|
@ -79,7 +79,7 @@ namespace
|
|||
"The current number of counted pulses from counter b.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace
|
|||
{
|
||||
setMfctTPLStatusBits(
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xe0))
|
||||
.set(DefaultMessage("OK"))
|
||||
.add(Translate::Map(0x40 ,"SABOTAGE_ENCLOSURE", TestBit::Set))));
|
||||
|
@ -60,7 +60,7 @@ namespace
|
|||
"The current number of counted pulses from counter a.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0EFD3A"))
|
||||
);
|
||||
|
@ -70,7 +70,7 @@ namespace
|
|||
"The current number of counted pulses from counter b.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("8E40FD3A"))
|
||||
);
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
Copyright (C) 2020-2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
@see https://www.lansensystems.com/media/1282/mbus_data_format_lan-wmbus-r4_v11_rev_3.pdf
|
||||
*/
|
||||
|
||||
#include"meters_common_implementation.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Driver : public virtual MeterCommonImplementation
|
||||
{
|
||||
Driver(MeterInfo &mi, DriverInfo &di);
|
||||
};
|
||||
|
||||
static bool ok = registerDriver([](DriverInfo&di)
|
||||
{
|
||||
di.setName("lansenrp");
|
||||
di.setDefaultFields("name,id,status,total_routed_messages_counter,used_router_slots_counter,is_repeater_listening,timestamp");
|
||||
di.setMeterType(MeterType::Repeater);
|
||||
di.addLinkMode(LinkMode::C1);
|
||||
di.addDetection(MANUFACTURER_LAS, 0x32, 0x0b);
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
});
|
||||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
setMfctTPLStatusBits(
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xe0))
|
||||
.set(DefaultMessage("OK"))
|
||||
.add(Translate::Map(0x04 ,"LOW_BATTERY", TestBit::Set))));
|
||||
|
||||
addStringField(
|
||||
"status",
|
||||
"Meter status from tpl status field.",
|
||||
DEFAULT_PRINT_PROPERTIES |
|
||||
PrintProperty::STATUS | PrintProperty::INCLUDE_TPL_STATUS);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"total_routed_messages",
|
||||
"Number of total routed messages since power up",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"used_router_slots",
|
||||
"Used router slots (maximum 936)",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
.set(SubUnitNr(1))
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"software_version",
|
||||
"Software version of repeater",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::SoftwareVersion)
|
||||
);
|
||||
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
"is_repeater_listening",
|
||||
"Is the repeater listening (YES/NO)",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
.set(SubUnitNr(2)),
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("INPUT_BITS", Translate::MapType::IndexToString)
|
||||
.set(MaskBits(0x01))
|
||||
.add(Translate::Map(0x00, "NO", TestBit::Set))
|
||||
.add(Translate::Map(0x01, "YES", TestBit::Set))
|
||||
));
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"seconds_to_mode_change",
|
||||
"Seconds to mode change (Listen -> Sleep or Sleep -> Listen). Maximum 32767 seconds",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
.set(SubUnitNr(3))
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"listen_timer_value",
|
||||
"Value on parameter 'Listen timer'",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
.set(StorageNr(1))
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"pause_timer_value",
|
||||
"Value on parameter 'Pause timer'",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
.set(StorageNr(2))
|
||||
);
|
||||
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
"repeater_listening_on_weekdays",
|
||||
"Shows which weekday(s) repeater is listening (MO/TU/WE/TH/FR/SA/SU)",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
.set(StorageNr(3)),
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("INPUT_BITS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xffff))
|
||||
.add(Translate::Map(0x01 ,"SU", TestBit::Set))
|
||||
.add(Translate::Map(0x02 ,"MO", TestBit::Set))
|
||||
.add(Translate::Map(0x04 ,"TU", TestBit::Set))
|
||||
.add(Translate::Map(0x08 ,"WE", TestBit::Set))
|
||||
.add(Translate::Map(0x10 ,"TH", TestBit::Set))
|
||||
.add(Translate::Map(0x20 ,"FR", TestBit::Set))
|
||||
.add(Translate::Map(0x40 ,"SA", TestBit::Set))
|
||||
));
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"start_time_value",
|
||||
"Value on parameter 'Start time', shown as minusted after midnight (-1=Not used)",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
.set(StorageNr(4))
|
||||
);
|
||||
|
||||
addStringFieldWithExtractor(
|
||||
"meter_datetime",
|
||||
"Date and time when the meter sent the telegram.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"battery",
|
||||
"Battery voltage.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Test: REPEAT lansenrp 00035946 NOKEY
|
||||
// telegram=|54443330465903000B327A2B0000402F2F04FD3A946709008240FD3A600002FD0F9500818040FD3A0084C040FD3A8838000042FD3A28008201FD3A8C05C101FD3A7F8202FD3A3804066D35122EFB2B0002FD46D00C|
|
||||
// {"media":"reserved","meter":"lansenrp","name":"REPEAT","id":"00035946","battery_v":3.28,"listen_timer_value_counter":40,"pause_timer_value_counter":1420,"seconds_to_mode_change_counter":14472,"start_time_value_counter":1080,"total_routed_messages_counter":616340,"used_router_slots_counter":96,"is_repeater_listening":"NO","meter_datetime":"2023-11-27 14:18:53","repeater_listening_on_weekdays":"FR MO SA SU TH TU WE","software_version":"0095","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |REPEAT;00035946;OK;616340;96;NO;1111-11-11 11:11.11
|
||||
|
||||
// telegram=|54443330465903000B327A2B0400402F2F04FD3A946709008240FD3A600002FD0F9500818040FD3A0184C040FD3A8838000042FD3A28008201FD3A8C05C101FD3A088202FD3A3804066D35122EFB2B0002FD46D00C|
|
||||
// {"media":"reserved","meter":"lansenrp","name":"REPEAT","id":"00035946","battery_v":3.28,"listen_timer_value_counter":40,"pause_timer_value_counter":1420,"seconds_to_mode_change_counter":14472,"start_time_value_counter":1080,"total_routed_messages_counter":616340,"used_router_slots_counter":96,"is_repeater_listening":"YES","meter_datetime":"2023-11-27 14:18:53","repeater_listening_on_weekdays":"WE","software_version":"0095","status":"POWER_LOW","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |REPEAT;00035946;POWER_LOW;616340;96;YES;1111-11-11 11:11.11
|
|
@ -49,7 +49,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ namespace
|
|||
"Unique asynchronous message number.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AccessNumber)
|
||||
|
@ -80,7 +80,7 @@ namespace
|
|||
"Minutes since last manual test.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
|
|
|
@ -36,10 +36,10 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("on_time_h");
|
||||
addOptionalLibraryFields("on_time_h");
|
||||
setMfctTPLStatusBits(
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xe0))
|
||||
.set(DefaultMessage("OK"))
|
||||
.add(Translate::Map(0x40 ,"SABOTAGE_ENCLOSURE", TestBit::Set))));
|
||||
|
@ -55,7 +55,7 @@ namespace
|
|||
"The current temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::AutoSigned,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -66,7 +66,7 @@ namespace
|
|||
"The current humidity.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::RelativeHumidity,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::RelativeHumidity)
|
||||
|
@ -77,7 +77,7 @@ namespace
|
|||
"The average temperature over the last hour.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::AutoSigned,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -89,7 +89,7 @@ namespace
|
|||
"The average humidity over the last hour.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::RelativeHumidity,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::RelativeHumidity)
|
||||
|
@ -101,7 +101,7 @@ namespace
|
|||
"The average temperature over the last 24 hours.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::AutoSigned,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -113,7 +113,7 @@ namespace
|
|||
"The average humidity over the last 24 hours.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::RelativeHumidity,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::RelativeHumidity)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2021-2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
Copyright (C) 2021-2024 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -34,6 +34,7 @@ namespace
|
|||
di.addDetection(MANUFACTURER_LSE, 0x07, 0x18);
|
||||
di.addDetection(MANUFACTURER_LSE, 0x07, 0x16);
|
||||
di.addDetection(MANUFACTURER_LSE, 0x07, 0x17);
|
||||
di.addDetection(MANUFACTURER_LSE, 0x07, 0xd8);
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
});
|
||||
|
||||
|
@ -44,7 +45,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -55,7 +56,7 @@ namespace
|
|||
"The water consumption at the due date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -77,7 +78,7 @@ namespace
|
|||
"The water consumption at the what date?",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -105,7 +106,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -207,3 +208,8 @@ namespace
|
|||
// telegram=|2D4465329933961318067ADA000000_0C13567100004C1300000000426CFFFF02BB560000326CFFFF046D2307A12C|
|
||||
// {"media":"warm water","meter":"lse_07_17","name":"Water","id":"13963399","total_m3":7.156,"due_date_m3":0,"due_date":"2127-15-31","what_date_m3":7,"what_date":"2021-11-30","error_code":"OK","error_date":"2127-15-31","device_date_time":"2021-12-01 07:35","meter_version":"11","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Water;13963399;7.156;0;2127-15-31;OK;2127-15-31;2021-12-01 07:35;1111-11-11 11:11.11
|
||||
|
||||
// Test: Water2 lse_07_17 09993623 NOKEY
|
||||
// telegram=|2d44653223369909d8077a80000000046d130aed2B0c13233332004c1351762700426cdf2c326cffff02BB560000|
|
||||
// {"device_date_time": "2023-11-13 10:19","due_date": "2022-12-31","due_date_m3": 277.651,"error_code": "OK","error_date": "2127-15-31","id": "09993623","media": "water","meter": "lse_07_17","name": "Water2","timestamp": "1111-11-11T11:11:11Z","total_m3": 323.323}
|
||||
// |Water2;09993623;323.323;277.651;2022-12-31;OK;2127-15-31;2023-11-13 10:19;1111-11-11 11:11.11
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -66,7 +66,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -87,7 +87,7 @@ namespace
|
|||
"Heat cost allocation at the most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -108,7 +108,7 @@ namespace
|
|||
"Duration since last measurement.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DurationSinceReadout)
|
||||
|
|
|
@ -36,8 +36,8 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("meter_datetime,model_version,parameter_set");
|
||||
addOptionalFlowRelatedFields("flow_temperature_c,return_temperature_c");
|
||||
addOptionalLibraryFields("meter_datetime,model_version,parameter_set");
|
||||
addOptionalLibraryFields("flow_temperature_c,return_temperature_c");
|
||||
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
"status",
|
||||
|
@ -52,7 +52,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -66,7 +66,7 @@ namespace
|
|||
"The total heat energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -77,7 +77,7 @@ namespace
|
|||
"The total heating media volume recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -88,7 +88,7 @@ namespace
|
|||
"The current heat media volume flow.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -99,7 +99,7 @@ namespace
|
|||
"The current power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::PowerW)
|
||||
|
@ -110,7 +110,7 @@ namespace
|
|||
"The difference between flow and return media temperatures.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::AutoSigned,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::TemperatureDifference)
|
||||
|
@ -121,7 +121,7 @@ namespace
|
|||
"The most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES | PrintProperty::HIDE,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Date)
|
||||
|
@ -134,7 +134,7 @@ namespace
|
|||
"The total water consumption at the historic date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
Copyright (C) 2021 Olli Salonen (gpl-3.0-or-later)
|
||||
Copyright (C) 2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
Copyright (C) 2022-2023 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -39,8 +39,8 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("meter_date,fabrication_no,operating_time_h,on_time_h,on_time_at_error_h,meter_datetime");
|
||||
addOptionalFlowRelatedFields("total_m3,total_backward_m3,volume_flow_m3h");
|
||||
addOptionalLibraryFields("meter_date,fabrication_no,operating_time_h,on_time_h,on_time_at_error_h,meter_datetime");
|
||||
addOptionalLibraryFields("total_m3,total_backward_m3,volume_flow_m3h");
|
||||
|
||||
/* If the meter is recently commissioned, the target water consumption value is bogus.
|
||||
The bits store 0xffffffff. Should we deal with this? Now a very large value is printed in the json.
|
||||
|
@ -51,7 +51,7 @@ namespace
|
|||
"The total water consumption recorded at the beginning of this month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -74,7 +74,7 @@ namespace
|
|||
"The total water consumption recorded at the beginning of this month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -130,7 +130,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -207,13 +207,13 @@ namespace
|
|||
|
||||
// Test: Mino minomess 15503451 NOKEY
|
||||
// telegram=|6644496A1064035514377251345015496A0007EE0050052F2F#0C1359000000026CBE2B82046CA12B8C0413FFFFFFFF8D0493132CFBFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02FD1700002F2F|
|
||||
// {"media":"water","meter":"minomess","name":"Mino","id":"15503451","meter_date":"2021-11-30","total_m3":0.059,"target_m3":244444.442,"target_date":"2021-11-01","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Mino;15503451;0.059;244444.442;OK;1111-11-11 11:11.11
|
||||
// {"media":"water","meter":"minomess","name":"Mino","id":"15503451","meter_date":"2021-11-30","total_m3":0.059,"target_date":"2021-11-01","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Mino;15503451;0.059;null;OK;1111-11-11 11:11.11
|
||||
|
||||
// Test: Minowired minomess 57575757 NOKEY
|
||||
// telegram=|6874746808007257575757496A000712000000_0C7857575757046D2414DE280413000000000C943C000000004413FFFFFFFF426CFFFF840113FFFFFFFF82016CFFFFC40113FFFFFFFFC2016CFFFF840213FFFFFFFF82026CFFFF043B000000000422E62F000004260000000034220000000002FD1700001F5716|
|
||||
// {"media":"water","meter":"minomess","name":"Minowired","id":"57575757","fabrication_no":"57575757","operating_time_h":0,"on_time_h":12262,"on_time_at_error_h":0,"meter_datetime":"2022-08-30 20:36","total_m3":0,"total_backward_m3":0,"volume_flow_m3h":0,"target_m3":4294967.295,"target_date":"2127-15-31","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Minowired;57575757;0;4294967.295;OK;1111-11-11 11:11.11
|
||||
// {"media":"water","meter":"minomess","name":"Minowired","id":"57575757","fabrication_no":"57575757","operating_time_h":0,"on_time_h":12262,"on_time_at_error_h":0,"meter_datetime":"2022-08-30 20:36","total_m3":0,"total_backward_m3":0,"volume_flow_m3h":0,"target_m3":-0.001,"target_date":"2127-15-31","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Minowired;57575757;0;-0.001;OK;1111-11-11 11:11.11
|
||||
|
||||
// Test: Zenner_cold minomess 21314151 NOKEY
|
||||
// telegram=|6644496A4425155518377251413121496A0116360050052F2F_0C1355000000026CEC2182046CE1218C0413000000808D0493132C33FE00008000008000008000008000008000008000008000008000008000008000008000008000008000008002FD1700002F2F|
|
||||
|
@ -223,4 +223,4 @@ namespace
|
|||
// Test: Zenner_warm minomess 51413121 NOKEY
|
||||
// telegram=|6644496A8753155518377221314151496A0106300050052F2F_0C1357000000026CEC2182046CE1218C0413000000808D0493132C33FE00008000008000008000008000008000008000008000008000008000008000008000008000008000008002FD1700002F2F|
|
||||
// {"media":"warm water","meter":"minomess","name":"Zenner_warm","id":"51413121","meter_date":"2023-01-12","total_m3":0.057,"target_m3":80000,"target_date":"2023-01-01","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Zenner_warm;51413121;0.057;80000;OK;1111-11-11 11:11.11
|
||||
// |Zenner_warm;51413121;0.057;80000;OK;1111-11-11 11:11.11
|
||||
|
|
|
@ -107,5 +107,5 @@ namespace
|
|||
// Comment: There is a problem in the decoding here, the data stored inside the telegram does not seem to properly encode/decode the year....
|
||||
// We should not report a current_date with a full year, if the year is actually not part of the telegram.
|
||||
// telegram=|2F446850313233347462A2_069F255900B029310000000306060906030609070606050509050505050407040605070500|
|
||||
// {"media":"warm water","meter":"mkradio3","name":"Duschen","id":"34333231","total_m3":13.8,"target_m3":8.9,"current_date":"2023-04-27T02:00:00Z","prev_date":"2018-12-31T02:00:00Z","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Duschen;34333231;13.8;8.9;2023-04-27T02:00:00Z;2018-12-31T02:00:00Z;1111-11-11 11:11.11
|
||||
// {"media":"warm water","meter":"mkradio3","name":"Duschen","id":"34333231","total_m3":13.8,"target_m3":8.9,"current_date":"2024-04-27T02:00:00Z","prev_date":"2018-12-31T02:00:00Z","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Duschen;34333231;13.8;8.9;2024-04-27T02:00:00Z;2018-12-31T02:00:00Z;1111-11-11 11:11.11
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace
|
|||
"The total water consumption recorded at the end of previous year.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -58,7 +58,7 @@ namespace
|
|||
"Date when previous year ended.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Date)
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace
|
|||
FieldMatcher::build()
|
||||
.set(DifVifKey("02FF20")),
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0x000f))
|
||||
.set(DefaultMessage("OK"))
|
||||
.add(Translate::Map(0x01 ,"DRY", TestBit::Set))
|
||||
|
@ -60,7 +60,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -71,7 +71,7 @@ namespace
|
|||
"The total water consumption recorded at the beginning of this month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -83,7 +83,7 @@ namespace
|
|||
"The water temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -95,7 +95,7 @@ namespace
|
|||
"The external temperature outside of the meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Any)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -108,7 +108,7 @@ namespace
|
|||
"The lowest external temperature outside of the meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -119,7 +119,7 @@ namespace
|
|||
"The maximum flow recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -136,7 +136,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0x000f),
|
||||
"",
|
||||
{
|
||||
|
@ -159,7 +159,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"DRY",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x0070),
|
||||
"",
|
||||
{
|
||||
|
@ -186,7 +186,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"REVERSED",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x0380),
|
||||
"",
|
||||
{
|
||||
|
@ -213,7 +213,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"LEAKING",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x1c00),
|
||||
"",
|
||||
{
|
||||
|
@ -240,7 +240,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"BURSTING",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0xe000),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -29,7 +29,6 @@ namespace
|
|||
di.setName("munia");
|
||||
di.setDefaultFields("name,id,current_temperature_c,current_relative_humidity_rh,timestamp");
|
||||
di.setMeterType(MeterType::TempHygroMeter);
|
||||
di.addLinkMode(LinkMode::MBUS);
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
di.addDetection(MANUFACTURER_WEP, 0x1b, 0x02);
|
||||
di.addDetection(MANUFACTURER_WEP, 0x1b, 0x04);
|
||||
|
@ -48,7 +47,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -63,7 +62,7 @@ namespace
|
|||
"The current temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -74,7 +73,7 @@ namespace
|
|||
"The current relative humidity.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::RelativeHumidity,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::RelativeHumidity)
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace
|
|||
"Et+ the total 3-phase active positive energy.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -61,7 +61,7 @@ namespace
|
|||
"P+ the 3-phase active positive power.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
"Er+ the total 3-phase reactive positive energy.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -89,7 +89,7 @@ namespace
|
|||
"Q+ the 3-phase reactive positive power.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -103,7 +103,7 @@ namespace
|
|||
"Part Et+ the total 3-phase active partial energy.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -117,7 +117,7 @@ namespace
|
|||
"P- the 3-phase active negative power.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -131,7 +131,7 @@ namespace
|
|||
"Part Er+ the total 3-phase reactive partial energy.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -145,7 +145,7 @@ namespace
|
|||
"Q- the 3-phase reactive negative power.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -159,7 +159,7 @@ namespace
|
|||
"PF the power factor.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless),
|
||||
|
@ -174,7 +174,7 @@ namespace
|
|||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ErrorFlags),
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xff))
|
||||
.set(DefaultMessage("OK"))
|
||||
));
|
||||
|
@ -186,7 +186,7 @@ namespace
|
|||
"I1 Amperage for L1 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Amperage)
|
||||
|
@ -198,7 +198,7 @@ namespace
|
|||
"I2 Amperage for L2 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Amperage)
|
||||
|
@ -210,7 +210,7 @@ namespace
|
|||
"I3 Amperage for L3 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Amperage)
|
||||
|
@ -222,7 +222,7 @@ namespace
|
|||
"L1-N Voltage for L1 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -234,7 +234,7 @@ namespace
|
|||
"L2-N Voltagefor L2 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -246,7 +246,7 @@ namespace
|
|||
"L3-N Voltage for L3 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -260,7 +260,7 @@ namespace
|
|||
"P1 Power for L1 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -273,7 +273,7 @@ namespace
|
|||
"P2 Power for L2 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -286,7 +286,7 @@ namespace
|
|||
"P3 Power for L3 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -299,7 +299,7 @@ namespace
|
|||
"Q1 Power for L1 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -312,7 +312,7 @@ namespace
|
|||
"Q2 Power for L2 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -325,7 +325,7 @@ namespace
|
|||
"Q3 Power for L3 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -338,7 +338,7 @@ namespace
|
|||
"PF1 the power factor for L1 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
|
@ -351,7 +351,7 @@ namespace
|
|||
"PF2 the power factor for L2 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
|
@ -364,7 +364,7 @@ namespace
|
|||
"PF3 the power factor for L3 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
|
@ -377,7 +377,7 @@ namespace
|
|||
"L1-L2 Voltage between phases.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -389,7 +389,7 @@ namespace
|
|||
"L2-L3 Voltage between phases.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -401,7 +401,7 @@ namespace
|
|||
"L3-L1 Voltage between phases.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -413,7 +413,7 @@ namespace
|
|||
"I Neutral amperage.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Amperage)
|
||||
|
@ -426,7 +426,7 @@ namespace
|
|||
"Frequency in 0.1 Hz",
|
||||
DEFAULT_PRINT_PROPERTIES | PrintProperty::HIDE,
|
||||
Quantity::Frequency,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("05FF5A"))
|
||||
);
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
"The total energy backward (production) recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -87,7 +87,7 @@ namespace
|
|||
"The current power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -98,7 +98,7 @@ namespace
|
|||
"The current power production.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("fabrication_no,software_version");
|
||||
addOptionalLibraryFields("fabrication_no,software_version");
|
||||
|
||||
addStringField(
|
||||
"status",
|
||||
|
@ -48,7 +48,7 @@ namespace
|
|||
"The current temperature.",
|
||||
PrintProperty::REQUIRED,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -59,7 +59,7 @@ namespace
|
|||
"The average temperature over the last hour.",
|
||||
PrintProperty::REQUIRED,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -71,7 +71,7 @@ namespace
|
|||
"The average temperature over the last 24 hours.",
|
||||
PrintProperty::REQUIRED,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -83,7 +83,7 @@ namespace
|
|||
"The current relative humidity.",
|
||||
PrintProperty::REQUIRED,
|
||||
Quantity::RelativeHumidity,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::RelativeHumidity)
|
||||
|
@ -94,7 +94,7 @@ namespace
|
|||
"The average relative humidity over the last hour.",
|
||||
PrintProperty::REQUIRED,
|
||||
Quantity::RelativeHumidity,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::RelativeHumidity)
|
||||
|
@ -106,7 +106,7 @@ namespace
|
|||
"The average relative humidity over the last 24 hours.",
|
||||
PrintProperty::REQUIRED,
|
||||
Quantity::RelativeHumidity,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::RelativeHumidity)
|
||||
|
@ -118,7 +118,7 @@ namespace
|
|||
|
||||
// Test: Tempo piigth 10000284 NOKEY
|
||||
// telegram=|68383868080072840200102941011B04000000_0265C0094265A509B20165000002FB1A900142FB1A6901B201FB1A00000C788402001002FD0F21000FC016|
|
||||
// {"media":"room sensor","meter":"piigth","name":"Tempo","id":"10000284","fabrication_no":"10000284","software_version":"0021","status":"OK","temperature_c":24.96,"average_temperature_1h_c":24.69,"average_temperature_24h_c":null,"relative_humidity_rh":40,"relative_humidity_1h_rh":36.1,"relative_humidity_24h_rh":null,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// {"media":"room sensor","meter":"piigth","name":"Tempo","id":"10000284","fabrication_no":"10000284","software_version":"0021","status":"OK","temperature_c":24.96,"average_temperature_1h_c":24.69,"relative_humidity_rh":40,"relative_humidity_1h_rh":36.1,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Tempo;10000284;OK;24.96;40;1111-11-11 11:11.11
|
||||
|
||||
// telegram=|68383868080072840200102941011B06000000_02653F0A4265000A820165CA0902FB1A4F0142FB1A53018201FB1A5E010C788402001002FD0F21000F1916|
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -59,7 +59,7 @@ namespace
|
|||
"The total amount of water that has passed through this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -70,7 +70,7 @@ namespace
|
|||
"The active power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -81,7 +81,7 @@ namespace
|
|||
"The flow of water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -92,7 +92,7 @@ namespace
|
|||
"The forward temperature of the water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -103,7 +103,7 @@ namespace
|
|||
"The return temperature of the water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
|
@ -124,7 +124,7 @@ namespace
|
|||
"The energy consumption recorded by this meter at the set date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -136,7 +136,7 @@ namespace
|
|||
"The amount of water that had passed through this meter at the set date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -148,7 +148,7 @@ namespace
|
|||
"The maximum forward temperature of the water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -160,7 +160,7 @@ namespace
|
|||
"The maximum return temperature of the water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
|
@ -172,14 +172,14 @@ namespace
|
|||
"The maximum forward flow of water through this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
.set(StorageNr(1))
|
||||
);
|
||||
|
||||
addOptionalCommonFields("operating_time_h,on_time_h,on_time_at_error_h,meter_datetime");
|
||||
addOptionalLibraryFields("operating_time_h,on_time_h,on_time_at_error_h,meter_datetime");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ namespace
|
|||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addOptionalCommonFields("meter_datetime");
|
||||
addOptionalFlowRelatedFields("total_m3,total_forward_m3,total_backward_m3,flow_temperature_c,volume_flow_m3h");
|
||||
addOptionalLibraryFields("meter_datetime,on_time_h");
|
||||
addOptionalLibraryFields("total_m3,total_forward_m3,total_backward_m3,flow_temperature_c,volume_flow_m3h");
|
||||
|
||||
addStringField(
|
||||
"status",
|
||||
|
@ -59,7 +59,7 @@ namespace
|
|||
"The total water consumption at the end of the previous billing period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -71,7 +71,7 @@ namespace
|
|||
"The total media volume flowing forward at the end of previous billing period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -84,7 +84,7 @@ namespace
|
|||
"The total media volume flowing backward at the end of the previous billing period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -92,6 +92,16 @@ namespace
|
|||
.add(VIFCombinable::BackwardFlow)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"battery",
|
||||
"Percentage of battery remaining.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("01FD74")),
|
||||
Unit::PERCENTAGE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,5 +113,10 @@ namespace
|
|||
// Test: AxiomaWater q400 72727273 NOKEY
|
||||
// Comment: Test Axioma W1 telegram with additional fields compared to the older q400 meter.
|
||||
// telegram=|5E4409077372727210077A710050052F2F_046D0110A92704130022000004933B0000000004933C00000000023B000002592A0A446D0000A12744130000000044933B0000000044933C0000000001FD74622F2F2F2F2F2F2F2F2F2F2F2F2F2F|
|
||||
// {"media":"water","meter":"q400","name":"AxiomaWater","id":"72727273","meter_datetime":"2021-07-09 16:01","total_m3":8.704,"total_forward_m3":0,"total_backward_m3":0,"flow_temperature_c":26.02,"volume_flow_m3h":0,"status":"OK","set_datetime":"2021-07-01 00:00","consumption_at_set_date_m3":0,"forward_at_set_date_m3":0,"backward_at_set_date_m3":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// {"media":"water","meter":"q400","name":"AxiomaWater","id":"72727273","meter_datetime":"2021-07-09 16:01","total_m3":8.704,"total_forward_m3":0,"total_backward_m3":0,"flow_temperature_c":26.02,"volume_flow_m3h":0,"status":"OK","set_datetime":"2021-07-01 00:00","consumption_at_set_date_m3":0,"forward_at_set_date_m3":0,"backward_at_set_date_m3":0,"battery_pct":98,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |AxiomaWater;72727273;8.704;1111-11-11 11:11.11
|
||||
|
||||
// Test: M q400 05829163 NOKEY
|
||||
// telegram=|544409076391820510077ABF100000046D2A0DC62C0420E80F430104130000000004933B0000000004933C00000000023B00000259F0D8446D0000C12C44130000000044933B0000000044933C0000000001FD7461|
|
||||
// {"backward_at_set_date_m3": 0,"battery_pct": 97,"consumption_at_set_date_m3": 0,"flow_temperature_c": -100,"forward_at_set_date_m3": 0,"id": "05829163","media": "water","meter": "q400","meter_datetime": "2022-12-06 13:42","name": "M","on_time_h": 5881.166667,"set_datetime": "2022-12-01 00:00","status": "TEMPORARY_ERROR","timestamp": "1111-11-11T11:11:11Z","total_backward_m3": 0,"total_forward_m3": 0,"total_m3": 0,"volume_flow_m3h": 0}
|
||||
// |M;05829163;0;1111-11-11 11:11.11
|
||||
|
|
|
@ -59,7 +59,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -95,7 +95,7 @@ namespace
|
|||
"Heat cost allocation at the most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -117,7 +117,7 @@ namespace
|
|||
"Heat cost allocation at the most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -139,7 +139,7 @@ namespace
|
|||
"Heat cost allocation at the 8 billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -161,7 +161,7 @@ namespace
|
|||
"Heat cost allocation at the 17 billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -200,7 +200,7 @@ namespace
|
|||
"Forward media temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -222,8 +222,8 @@ namespace
|
|||
|
||||
// Test: zenner_heat qcaloric 25932395 NOKEY
|
||||
// telegram=|5E44496A95239325FD087A2CC050052F2F_0B6E030100426CDF2C4B6EFFFFFF82046CE1228B046E6200008D04EE132C3BFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2F2F2F2F|
|
||||
// {"media":"heat cost allocation","meter":"qcaloric","name":"zenner_heat","id":"25932395","status":"UNKNOWN_C0","current_consumption_hca":103,"set_date":"2022-12-31","consumption_at_set_date_hca":2444442,"set_date_1":"2022-12-31","consumption_at_set_date_1_hca":2444442,"set_date_8":"2023-02-01","consumption_at_set_date_8_hca":62,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |zenner_heat;25932395;103;2022-12-31;2444442;1111-11-11 11:11.11
|
||||
// {"media":"heat cost allocation","meter":"qcaloric","name":"zenner_heat","id":"25932395","status":"UNKNOWN_C0","current_consumption_hca":103,"set_date":"2022-12-31","set_date_1":"2022-12-31","set_date_8":"2023-02-01","consumption_at_set_date_8_hca":62,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |zenner_heat;25932395;103;2022-12-31;null;1111-11-11 11:11.11
|
||||
|
||||
// Comment: Normal telegram that fills in values.
|
||||
// telegram=|314493449392919034087a520000200b6e9700004b6e700200426c9f2ccb086e970000c2086cbe26326cffff046d2d16a227|
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -85,7 +85,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -106,7 +106,7 @@ namespace
|
|||
"The total energy consumption recorded at the last day of the previous month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(17))
|
||||
|
@ -128,7 +128,7 @@ namespace
|
|||
"The total energy consumption recorded at the last day of the previous year.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(1))
|
||||
|
@ -160,8 +160,11 @@ namespace
|
|||
vector<uchar> v;
|
||||
auto entry = it->second.second;
|
||||
hex2bin(entry.value.substr(0, 8), &v);
|
||||
t->addId(v.begin());
|
||||
std::string info = "*** " + entry.value.substr(0, 8) + " tpl-id (" + t->ids.back() + ")";
|
||||
// FIXME PROBLEM
|
||||
Address a;
|
||||
a.id = tostrprintf("%02x%02x%02x%02x", v[3], v[2], v[1], v[0]);
|
||||
t->addresses.push_back(a);
|
||||
std::string info = "*** " + entry.value.substr(0, 8) + " tpl-id (" + t->addresses.back().id + ")";
|
||||
t->addSpecialExplanation(entry.offset, 4, KindOfData::CONTENT, Understanding::FULL, info.c_str());
|
||||
|
||||
v.clear();
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -89,7 +89,7 @@ namespace
|
|||
"The total energy consumption recorded at key (billing) date",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -121,7 +121,7 @@ namespace
|
|||
info,
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -136,7 +136,7 @@ namespace
|
|||
"The time between the measurement and the sending of this telegram.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ActualityDuration)
|
||||
|
@ -147,7 +147,7 @@ namespace
|
|||
"How long the meter has been in an error state and unable to measure values, while powered up.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::AtError)
|
||||
.set(VIFRange::OnTime)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Ładowanie…
Reference in New Issue