Porównaj commity

...

37 Commity

Autor SHA1 Wiadomość Data
Fredrik Öhrström 1a4169ed23
Merge pull request #1262 from PovilasID/patch-1
Documenting MQTT as telegram source
2024-04-29 23:19:23 +02:00
PovilasID aa4f1956e8
Documenting MQTT as telegram source 2024-04-29 19:49:52 +03:00
Fredrik Öhrström d90dbb196e Add another m,v,t combo for the lse_07_17 driver. 2024-04-15 08:44:14 +02:00
Fredrik Öhrström 14d021426a
Merge pull request #1245 from majonezz/patch-1
Avoid SIGSEGV in WMBusCUL::checkCULFrame
2024-04-14 16:13:26 +02:00
Michał Morański f32179a939
Avoid SIGSEGV in WMBusCUL::checkCULFrame
(cul) checkCULFrame "b2F4468506586269295620A17A2069F2"
(cul) no eol found yet, partial frame
(serial) received ascii "TMODE<0D><0A>b2F44685086625092957245C6A2069F2F6A06E0080000000000000000B9BF00000D0F0D11130512100F0F0F100F0F8E1F0F0E0D121310B241<0D><0A>b4E44B61065960200023732117A0E004005E4B5FD2A1E3DCCC84F38BDF21FD05D506BF685D50CB3AD9644F9FF7C893BF9DD0D2B64C85F703707B1965C69261E8CDF85046CDDC38F1336D67750E933854BA0C9A91240A18556E6064B<0D><0A>"
(cul) checkCULFrame "b2F4468506586269295620A17A2069F2TMODE<0D><0A>b2F44685086625092957245C6A2069F2F6A06E0080000000000000000B9BF00000D0F0D11130512100F0F0F100F0F8E1F0F0E0D121310B241<0D><0A>b4E44B61065960200023732117A0E004005E4B5FD2A1E3DCCC84F38BDF21FD05D506BF685D50CB3AD9644F9FF7C893BF9DD0D2B64C85F703707B1965C69261E8CDF85046CDDC38F1336D67750E933854BA0C9A91240A18556E6064B<0D><0A>"
(cul) bad hex for LQI and RSSI "MODE"
(cul) warning: the LQI and RSSI hex string is not properly formatted!

Thread 2 "wmbusmeters" received signal SIGSEGV, Segmentation fault.
0x571c718f in WMBusCUL::checkCULFrame (this=0xf0a03480, data=std::vector of length 339, capacity 339 = {...}, hex_frame_length=0xf07fe680,
    payload=std::vector of length 0, capacity 0, rssi_dbm=0xf07fe6c0) at src/wmbus_cul.cc:336
336         uint lqi = lqi_rssi[0]>>1;
(gdb)
2024-04-14 15:16:56 +02:00
Fredrik Öhrström a32fcfdf9a When generating IV for AES-CTR zero out H and R bit. 2024-04-13 13:42:25 +02:00
Fredrik Öhrström efcc41d107 Add support for GJ VIF. 2024-04-09 20:47:42 +02:00
Fredrik Öhrström a69e547a17 Update drivers with signedness. Fix tests. 2024-04-09 11:11:17 +02:00
Fredrik Öhrström 23f2279a64 Separate VIF scaling and DIF signedness. Default to signed DIF binary integers. 2024-04-09 10:41:30 +02:00
Fredrik Öhrström 05edab0882 Add help on intsalling jq. 2024-04-08 17:02:35 +02:00
Fredrik Öhrström ff72e1debc Add dynamic driver lookup bits translation to strings. 2024-04-04 20:59:03 +02:00
Fredrik Öhrström c1509f6139
Merge pull request #1218 from jsreynaud/better_message_for_vife
Adding a better description of combinable extension vife
2024-03-29 16:19:50 +01:00
Fredrik Öhrström 9facddf019 Add support for the same fully specified secondary address printed by libmbus after doing a bus scan. 2024-03-28 12:41:00 +01:00
Fredrik Öhrström 9a34a55abb Fail decoding if too many difes/vifes are found. 2024-03-28 12:41:00 +01:00
Fredrik Öhrström 465a450a8b
Merge pull request #1196 from avandorp/patch-1
topaseskr: Fix wording for date values
2024-03-22 20:23:08 +01:00
Jean-Samuel REYNAUD 9576550f85
Adding a better description of combinable extension vife 2024-03-22 16:25:49 +01:00
Fredrik Öhrström 1f2cd10160 Update README. 2024-03-03 19:40:06 +01:00
Fredrik Öhrström 8c09f7b2d8 The required field does not contribute to testing of the address expressions before. 2024-03-03 19:34:00 +01:00
Fredrik Öhrström 3247a4a576 Update README. 2024-03-03 15:44:59 +01:00
Fredrik Öhrström 23779cb9f7 Add option --identitymode=... 2024-03-03 12:57:40 +01:00
Fredrik Öhrström 5962e727ff Handle more address rules. 2024-03-02 22:46:50 +01:00
Arthur van Dorp 03d95e780e topaseskr: Fix wording for date values
Those are period end dates, not start dates. That was my bad, sorry.
2024-03-02 21:06:59 +01:00
Fredrik Öhrström 11c83c1f37 Remove unused code. 2024-03-02 15:42:39 +01:00
Fredrik Öhrström 7634b95438 New advanced addressing works. 2024-03-02 15:30:25 +01:00
Fredrik Öhrström 78e7c47503 Add filter_out to address expression. 2024-03-01 12:00:49 +01:00
Fredrik Öhrström 0c98b474bb Fix tests. 2024-02-27 11:52:45 +01:00
Fredrik Öhrström 9d27ab3fb3 New source file address.cc for mbus addressing. 2024-02-26 11:44:47 +01:00
Fredrik Öhrström c21efd1d69
Merge pull request #1187 from testuser7/docker-tag
Improve workflow syntax
2024-02-23 08:51:43 +01:00
testuser7 67230b4213 Improve workflow syntax 2024-02-22 18:52:59 +01:00
Fredrik Öhrström 569efa3af2 Version 1.16.1 2024-02-22 2024-02-22 18:46:05 +01:00
Fredrik Öhrström 58dd9d32ff
Merge pull request #1186 from testuser7/docker-tag
Fix docker tag creation
2024-02-22 18:45:13 +01:00
testuser7 7f7f7e4df4 Fix docker tag creation 2024-02-22 18:39:41 +01:00
Fredrik Öhrström af83f15ca9 Version 1.16.0 2024-02-22 2024-02-22 17:49:53 +01:00
Fredrik Öhrström 0587c6d1dd
Merge pull request #1185 from jsreynaud/patch-1
Update README.md
2024-02-22 17:46:34 +01:00
Jean-Samuel Reynaud dd45c14970
Update README.md
Fix an inconstancy between code that use --driverslib and doc that say --dirverlib...
2024-02-22 16:28:14 +01:00
Fredrik Öhrström 097f91fac0 Add dynaic driver add_combinable and storage_nr. 2024-02-15 11:40:30 +01:00
Fredrik Öhrström dbd99698b8 Version 1.15.0 2024-02-14 2024-02-14 17:52:32 +01:00
122 zmienionych plików z 3479 dodań i 1920 usunięć

Wyświetl plik

@ -11,8 +11,8 @@ on:
env:
DOCKERHUB_IMAGE: ${{ github.repository }}
IMAGE_TAG: |
${{ github.ref_type == 'tag' && (contains(github.ref_name, '-RC') &&
join('candidate-', github.ref_name) || join('release-', github.ref_name)) || 'latest' }}
${{ github.ref_type == 'tag' && format('{0}-{1}', (contains(github.ref_name, '-RC') &&
'candidate' || 'release'), github.ref_name) || 'latest' }}
jobs:
build:

38
CHANGES
Wyświetl plik

@ -1,3 +1,41 @@
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.

Wyświetl plik

@ -1,5 +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
@ -153,6 +152,7 @@ $(BUILD)/%.o: src/%.c $(wildcard src/%.h)
$(CXX) -I/usr/include/libxml2 -fpermissive $(CXXFLAGS) $< -MMD -c -o $@
PROG_OBJS:=\
$(BUILD)/address.o \
$(BUILD)/aes.o \
$(BUILD)/aescmac.o \
$(BUILD)/bus.o \

Wyświetl plik

@ -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.
@ -130,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
@ -173,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
```
@ -217,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
@ -395,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]
@ -415,10 +450,11 @@ As {options} you can use:
--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
--driverdir=<dir> load all drivers in dir
--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
@ -832,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,

Wyświetl plik

@ -1,5 +1,7 @@
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 && \

Wyświetl plik

@ -0,0 +1,2 @@
telegram=|7B4479169977997730378C208B900F002C25E4EF0A002EA98E7D58B3ADC57299779977991611028B005087102F2F#0DFD090F34302e3030562030303030303030300D790E31323334353637383839595345310DFD100AAAAAAAAAAAAAAAAAAAAA0D780E31323334353637383930594553312F2F2F2F2F2F2F2F2F2F2F|
telegram=|7B4479169977997730378C20F0900F002C2549EE0A0077C19D3D1A08ABCD729977997779161102F0005007102F2F#0702F5C3FA000000000007823C5407000000000000841004E081020084200415000000042938AB000004A9FF01FA0A000004A9FF02050A000004A9FF03389600002F2F2F2F2F2F2F2F2F2F2F2F2F|

Wyświetl plik

@ -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

Wyświetl plik

@ -0,0 +1,4 @@
telegram=|414493447514916746377275149167934446044D000020_0C06490000004C0600000000426CFF2CCC080611000000C2086C1F3102FD170000326CFFFF046D330F1432|
telegram=|5b44934475149167463778077975149167934446040dff5f3500823d0000810007c006ffff49000000ff2c000000001f3111000000008000800080008000800080008000800080000000000B002f02fd170000046d390d1432488408|
telegram=|414493447514916746377275149167934446044D000020_0C06490000004C0600000000426CFF2CCC080611000000C2086C1F3102FD170000326CFFFF046D330F1432|
telegram=|5b44934475149167463778077975149167934446040dff5f3500823d0000810007c006ffff49000000ff2c000000001f3111000000008000800080008000800080008000800080000000000B002f02fd170000046d390d1432488408|

Wyświetl plik

@ -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
@ -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

656
src/address.cc 100644
Wyświetl plik

@ -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;
}

117
src/address.h 100644
Wyświetl plik

@ -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

Wyświetl plik

@ -617,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) {
@ -728,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);

Wyświetl plik

@ -53,10 +53,11 @@ 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;
@ -108,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")
{
@ -129,6 +130,15 @@ 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);
}
@ -176,37 +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.meter_shells = meter_shells;
mi.idsc = toIdsCommaSeparated(mi.ids);
mi.selected_fields = selected_fields;
c->meters.push_back(mi);
}

Wyświetl plik

@ -99,6 +99,7 @@ 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;

Wyświetl plik

@ -46,7 +46,7 @@ namespace
"Total cumulative active imported energy.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -58,7 +58,7 @@ namespace
"Total cumulative active imported energy per tariff.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -71,7 +71,7 @@ namespace
"Total cumulative active exported energy.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -85,7 +85,7 @@ namespace
"Total cumulative active exported energy per tariff.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -99,7 +99,7 @@ namespace
"Active tariff.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("01FF9300")),
Unit::NUMBER
@ -110,7 +110,7 @@ namespace
"Current transformer ratio (numerator).",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("04FFA015")),
Unit::FACTOR
@ -121,7 +121,7 @@ namespace
"Voltage transformer ratio (numerator).",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("04FFA115")),
Unit::FACTOR
@ -132,7 +132,7 @@ namespace
"Current transformer ratio (denominator).",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("04FFA215")),
Unit::FACTOR
@ -143,7 +143,7 @@ namespace
"Voltage transformer ratio (denominator).",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("04FFA315")),
Unit::FACTOR
@ -157,7 +157,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA600")),
Translate::Lookup()
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xffffffffffffffff))
.set(DefaultMessage("OK"))
));
@ -170,7 +170,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA700")),
Translate::Lookup()
.add(Translate::Rule("WARNING_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("WARNING_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xffffffffffffffff))
.set(DefaultMessage("OK"))
));
@ -183,7 +183,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA800")),
Translate::Lookup()
.add(Translate::Rule("INFORMATION_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("INFORMATION_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xffffffffffffffff))
.set(DefaultMessage(""))
));
@ -196,7 +196,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("07FFA900")),
Translate::Lookup()
.add(Translate::Rule("ALARM_FLAGS", Translate::Type::BitToString)
.add(Translate::Rule("ALARM_FLAGS", Translate::MapType::BitToString)
.set(MaskBits(0xfffffffffffffff))
.set(DefaultMessage("OK"))
));
@ -209,7 +209,7 @@ namespace
.set(MeasurementType::Instantaneous)
.set(DifVifKey("01FFAD00")),
Translate::Lookup()
.add(Translate::Rule("UNKNOWN", Translate::Type::BitToString)
.add(Translate::Rule("UNKNOWN", Translate::MapType::BitToString)
.set(MaskBits(0xff))
.set(DefaultMessage("OK"))
));
@ -236,7 +236,7 @@ namespace
"Power fail counter.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("04FF9800"))
);
@ -246,7 +246,7 @@ namespace
"Instantaneous total active imported power.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -258,7 +258,7 @@ namespace
"Instantaneous active imported power for L1 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -271,7 +271,7 @@ namespace
"Instantaneous active imported power for L2 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -284,7 +284,7 @@ namespace
"Instantaneous active imported power for L3 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -297,7 +297,7 @@ namespace
"Instantaneous total reactive imported power.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -310,7 +310,7 @@ namespace
"Instantaneous reactive imported power for L1 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -324,7 +324,7 @@ namespace
"Instantaneous reactive imported power for L2 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -338,7 +338,7 @@ namespace
"Instantaneous reactive imported power for L3 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -352,7 +352,7 @@ namespace
"Instantaneous total apparent imported power.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -365,7 +365,7 @@ namespace
"Instantaneous apparent imported power for L1 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -379,7 +379,7 @@ namespace
"Instantaneous apparent imported power for L2 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -393,7 +393,7 @@ namespace
"Instantaneous apparent imported power for L3 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -407,7 +407,7 @@ namespace
"Instantaneous voltage between L1 and neutral.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Voltage,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Voltage)
@ -420,7 +420,7 @@ namespace
"Instantaneous voltage between L2 and neutral.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Voltage,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Voltage)
@ -433,7 +433,7 @@ namespace
"Instantaneous voltage between L3 and neutral.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Voltage,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Voltage)
@ -446,7 +446,7 @@ namespace
"Instantaneous voltage between L1 and L2.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Voltage,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Voltage)
@ -459,7 +459,7 @@ namespace
"Instantaneous voltage between L2 and L3.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Voltage,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Voltage)
@ -472,7 +472,7 @@ namespace
"Instantaneous voltage between L3 and L1.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Voltage,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Voltage)
@ -485,7 +485,7 @@ namespace
"Instantaneous current in the L1 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Amperage,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Amperage)
@ -498,7 +498,7 @@ namespace
"Instantaneous current in the L2 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Amperage,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Amperage)
@ -511,7 +511,7 @@ namespace
"Instantaneous current in the L3 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Amperage,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Amperage)
@ -524,7 +524,7 @@ namespace
"Frequency of AC",
DEFAULT_PRINT_PROPERTIES,
Quantity::Frequency,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("0AFFD900")),
Unit::HZ,
@ -536,7 +536,7 @@ namespace
"Power factor.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("02FFE000")),
Unit::FACTOR,
@ -548,7 +548,7 @@ namespace
"Power factor for phase L1.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("02FFE0FF8100")),
Unit::FACTOR,
@ -560,7 +560,7 @@ namespace
"Power factor for phase L2.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("02FFE0FF8200")),
Unit::FACTOR,
@ -572,7 +572,7 @@ namespace
"Power factor.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("02FFE0FF8300")),
Unit::FACTOR,
@ -584,7 +584,7 @@ namespace
"Total power phase angle.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Angle,
VifScaling::NoneSigned,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("02FFD200")),
Unit::DEGREE,
@ -596,7 +596,7 @@ namespace
"Power phase angle for phase L1.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Angle,
VifScaling::NoneSigned,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("02FFD2FF8100")),
Unit::DEGREE,
@ -608,7 +608,7 @@ namespace
"Power phase angle for phase L2.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Angle,
VifScaling::NoneSigned,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("02FFD2FF8200")),
Unit::DEGREE,
@ -620,7 +620,7 @@ namespace
"Power phase angle for phase L3.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Angle,
VifScaling::NoneSigned,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("02FFD2FF8300")),
Unit::DEGREE,
@ -632,7 +632,7 @@ namespace
"Total cumulative reactive kvarh imported energy.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Reactive_Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -646,7 +646,7 @@ namespace
"Total cumulative reactive kvarh imported energy per tariff.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -660,7 +660,7 @@ namespace
"Total cumulative reactive kvarh exported energy.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Reactive_Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -674,7 +674,7 @@ namespace
"Total cumulative reactive kvarh exported energy per tariff.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -688,7 +688,7 @@ namespace
"The quadrant in which the current is measured.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("01FF9700")),
Unit::NUMBER
@ -699,7 +699,7 @@ namespace
"The quadrant in which the current is measured for phase L1.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("01FF97FF8100")),
Unit::NUMBER
@ -710,7 +710,7 @@ namespace
"The quadrant in which the current is measured for phase L2.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("01FF97FF8200")),
Unit::NUMBER
@ -721,7 +721,7 @@ namespace
"The quadrant in which the current is measured for phase L3.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("01FF97FF8300")),
Unit::NUMBER
@ -739,7 +739,7 @@ namespace
.set(SubUnitNr(1),SubUnitNr(2))
.add(VIFCombinableRaw(0)),
Translate::Lookup()
.add(Translate::Rule("OUTPUT", Translate::Type::BitToString)
.add(Translate::Rule("OUTPUT", Translate::MapType::BitToString)
.set(MaskBits(0xff))
));
@ -753,7 +753,7 @@ namespace
.set(SubUnitNr(3),SubUnitNr(4))
.add(VIFCombinableRaw(0)),
Translate::Lookup()
.add(Translate::Rule("INPUT", Translate::Type::BitToString)
.add(Translate::Rule("INPUT", Translate::MapType::BitToString)
.set(MaskBits(0xff))
));
@ -768,7 +768,7 @@ namespace
.set(SubUnitNr(3),SubUnitNr(4))
.add(VIFCombinableRaw(0)),
Translate::Lookup()
.add(Translate::Rule("INPUT", Translate::Type::BitToString)
.add(Translate::Rule("INPUT", Translate::MapType::BitToString)
.set(MaskBits(0xff))
));
@ -777,7 +777,7 @@ namespace
"Number of times input 1-2 counted a 1.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(SubUnitNr(3),SubUnitNr(4))
@ -790,7 +790,7 @@ namespace
"Resettable cumulative active imported energy.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -803,7 +803,7 @@ namespace
"Resettable cumulative active exported energy.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -817,7 +817,7 @@ namespace
"Resettable cumulative reactive imported energy.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -831,7 +831,7 @@ namespace
"Resettable cumulative reactive exported energy.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -845,7 +845,7 @@ namespace
"Number of times the resettable energy imported value has been reset.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRaw(0x7f71))
@ -857,7 +857,7 @@ namespace
"Number of times the resettable active energy exported value has been reset.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRaw(0x7f71))
@ -870,7 +870,7 @@ namespace
"Number of times the resettable reactive energy imported value has been reset.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRaw(0x7f71))
@ -883,7 +883,7 @@ namespace
"Number of times the resettable reactive energy exported value has been reset.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRaw(0x7f71))
@ -896,7 +896,7 @@ namespace
"Energy in co2.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Mass,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("0EFFF9C400")),
Unit::KG,
@ -908,7 +908,7 @@ namespace
"CO2 conversion factor (kg * 10-3 /kWh).",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("04FFA400")),
Unit::FACTOR
@ -919,7 +919,7 @@ namespace
"Energy in currency.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("0EFFF9C900"))
);
@ -929,7 +929,7 @@ namespace
"Currency conversion factor (curr * 10-3 /kWh).",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("04FFA500")),
Unit::FACTOR
@ -940,7 +940,7 @@ namespace
"Total cumulative apparent kvah imported energy.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Apparent_Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -954,7 +954,7 @@ namespace
"Total cumulative apparent kvah exported energy.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Apparent_Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -968,7 +968,7 @@ namespace
"Total imported active energy for L1 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -981,7 +981,7 @@ namespace
"Total imported active energy for L2 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -994,7 +994,7 @@ namespace
"Total imported active energy for L3 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1007,7 +1007,7 @@ namespace
"Total imported reactive energy for L1 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1021,7 +1021,7 @@ namespace
"Total imported reactive energy for L2 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1035,7 +1035,7 @@ namespace
"Total imported reactive energy for L3 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1049,7 +1049,7 @@ namespace
"Total imported apparent energy for L1 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1063,7 +1063,7 @@ namespace
"Total imported apparent energy for L2 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1077,7 +1077,7 @@ namespace
"Total imported apparent energy for L3 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1091,7 +1091,7 @@ namespace
"Total exported active energy for L1 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1105,7 +1105,7 @@ namespace
"Total exported active energy for L2 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1119,7 +1119,7 @@ namespace
"Total exported active energy for L3 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1133,7 +1133,7 @@ namespace
"Total exported reactive energy for L1 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1147,7 +1147,7 @@ namespace
"Total exported reactive energy for L2 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1161,7 +1161,7 @@ namespace
"Total exported reactive energy for L3 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1175,7 +1175,7 @@ namespace
"Total exported apparent energy for L1 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1189,7 +1189,7 @@ namespace
"Total exported apparent energy for L2 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1203,7 +1203,7 @@ namespace
"Total exported apparent energy for L3 phase.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1217,7 +1217,7 @@ namespace
"Active net energy total.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1230,7 +1230,7 @@ namespace
"Active net energy total for phase L1.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1244,7 +1244,7 @@ namespace
"Active net energy total for phase L2.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1258,7 +1258,7 @@ namespace
"Active net energy total for phase L3.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1272,7 +1272,7 @@ namespace
"Active net energy total.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1286,7 +1286,7 @@ namespace
"Active net reactive energy total for phase L1.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1301,7 +1301,7 @@ namespace
"Active net reactive energy total for phase L2.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1316,7 +1316,7 @@ namespace
"Active net reactive energy total for phase L3.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1331,7 +1331,7 @@ namespace
"Active net energy total.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1345,7 +1345,7 @@ namespace
"Active net apparent energy total for phase L1.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1360,7 +1360,7 @@ namespace
"Active net apparent energy total for phase L2.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -1375,7 +1375,7 @@ namespace
"Active net apparent energy total for phase L3.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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),
"",
{

Wyświetl plik

@ -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,17 +284,17 @@ 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|
// {"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}
// {"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|
// {"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}
// {"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

Wyświetl plik

@ -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)))
);
}

Wyświetl plik

@ -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)

Wyświetl plik

@ -30,13 +30,23 @@ void check_detection_triplets(DriverInfo *di, string file);
string check_field_name(const char *name, DriverDynamic *dd);
Quantity check_field_quantity(const char *quantity_s, DriverDynamic *dd);
VifScaling check_vif_scaling(const char *vif_scaling_s, DriverDynamic *dd);
DifSignedness check_dif_signedness(const char *dif_signedness_s, DriverDynamic *dd);
PrintProperties check_print_properties(const char *print_properties_s, DriverDynamic *dd);
string get_translation(XMQDoc *doc, XMQNode *node, string name, string lang);
string check_calculate(const char *formula, DriverDynamic *dd);
Unit check_display_unit(const char *display_unit, DriverDynamic *dd);
void check_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm, DriverDynamic *dd);
void check_set_vif_range(const char *vif_range_s, FieldMatcher *fm, DriverDynamic *dd);
bool checked_set_difvifkey(const char *difvifkey_s, FieldMatcher *fm, DriverDynamic *dd);
void checked_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm, DriverDynamic *dd);
void checked_set_vif_range(const char *vif_range_s, FieldMatcher *fm, DriverDynamic *dd);
void checked_set_storagenr_range(const char *storagenr_range_s, FieldMatcher *fm, DriverDynamic *dd);
void checked_set_tariffnr_range(const char *tariffnr_range_s, FieldMatcher *fm, DriverDynamic *dd);
void checked_set_subunitnr_range(const char *subunitnr_range_s, FieldMatcher *fm, DriverDynamic *dd);
Translate::MapType checked_map_type(const char *map_type_s, DriverDynamic *dd);
uint64_t checked_mask_bits(const char *mask_bits_s, DriverDynamic *dd);
uint64_t checked_value(const char *value_s, DriverDynamic *dd);
TestBit checked_test_type(const char *test_s, DriverDynamic *dd);
void checked_add_vif_combinable(const char *vif_range_s, FieldMatcher *fm, DriverDynamic *dd);
const char *line = "-------------------------------------------------------------------------------";
@ -55,12 +65,12 @@ bool DriverDynamic::load(DriverInfo *di, const string &file_name, const char *co
if (!content)
{
ok = xmqParseFile(doc, file.c_str(), NULL);
ok = xmqParseFile(doc, file.c_str(), NULL, 0);
}
else
{
file = "builtin";
ok = xmqParseBuffer(doc, content, content+strlen(content), NULL);
ok = xmqParseBuffer(doc, content, content+strlen(content), NULL, 0);
}
if (!ok) {
@ -100,6 +110,8 @@ bool DriverDynamic::load(DriverInfo *di, const string &file_name, const char *co
}
catch (...)
{
xmqFreeDoc(doc);
di->setDynamic(file, NULL);
return false;
}
}
@ -107,27 +119,22 @@ bool DriverDynamic::load(DriverInfo *di, const string &file_name, const char *co
DriverDynamic::DriverDynamic(MeterInfo &mi, DriverInfo &di) :
MeterCommonImplementation(mi, di), file_name_(di.getDynamicFileName())
{
XMQDoc *doc = di.getDynamicDriver();
assert(doc);
verbose("(driver) constructing driver %s from already loaded file %s\n",
di.name().str().c_str(),
fileName().c_str());
XMQDoc *doc = NULL;
try
{
doc = di.getDynamicDriver();
assert(doc);
verbose("(driver) constructing driver %s from already loaded file %s\n",
di.name().str().c_str(),
fileName().c_str());
xmqForeach(doc, NULL, "/driver/use", (XMQNodeCallback)add_use, this);
}
catch (...)
{
}
try
{
xmqForeach(doc, NULL, "/driver/field", (XMQNodeCallback)add_field, this);
}
catch (...)
catch(...)
{
xmqFreeDoc(doc);
}
}
@ -150,7 +157,7 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d
mvt.c_str(),
line,
line);
throw 1;
return XMQ_CONTINUE;
}
string mfct = fields[0];
@ -163,9 +170,9 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d
char a = mfct[0];
char b = mfct[1];
char c = mfct[2];
if (!(a >= 'A' && a < 'Z' &&
b >= 'A' && b < 'Z' &&
c >= 'A' && c < 'Z'))
if (!(a >= 'A' && a <= 'Z' &&
b >= 'A' && b <= 'Z' &&
c >= 'A' && c <= 'Z'))
{
warning("(driver) error in %s, bad manufacturer in mvt triplet: %s\n"
"%s\n"
@ -175,7 +182,7 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d
mfct.c_str(),
line,
line);
throw 1;
return XMQ_CONTINUE;
}
mfct_code = toMfctCode(a, b, c);
}
@ -193,7 +200,7 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d
mfct.c_str(),
line,
line);
throw 1;
return XMQ_CONTINUE;
}
}
@ -207,7 +214,7 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d
version,
line,
line);
throw 1;
return XMQ_CONTINUE;
}
if (type > 255 || type < 0)
@ -220,7 +227,7 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d
type,
line,
line);
throw 1;
return XMQ_CONTINUE;
}
string mfct_flag = manufacturerFlag(mfct_code);
@ -263,6 +270,9 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *
// The vif scaling is by default Auto but can be overriden for pesky fields.
VifScaling vif_scaling = check_vif_scaling(xmqGetString(doc, field, "vif_scaling"), dd);
// The dif signedness is by default Signed but can be overriden for pesky fields.
DifSignedness dif_signedness = check_dif_signedness(xmqGetString(doc, field, "dif_signedness"), dd);
// The properties are by default empty but can be specified for specific fields.
PrintProperties properties = check_print_properties(xmqGetString(doc, field, "attributes"), dd);
@ -282,6 +292,21 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *
// Check if there were any matches at all, if not, then disable the matcher.
match.active = num_matches > 0;
// Now find all matchers.
Translate::Lookup lookup = Translate::Lookup();
/*
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
.set(MaskBits(0x000f))
.set(DefaultMessage("OK"))
.add(Translate::Map(0x01 ,"DRY", TestBit::Set))
.add(Translate::Map(0x02 ,"REVERSE", TestBit::Set))
.add(Translate::Map(0x04 ,"LEAK", TestBit::Set))
.add(Translate::Map(0x08 ,"BURST", TestBit::Set))
));
*/
dd->tmp_lookup_ = &lookup;
int num_lookups = xmqForeach(doc, field, "lookup", (XMQNodeCallback)add_lookup, dd);
if (is_numeric)
{
if (calculate == "")
@ -292,6 +317,7 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *
properties,
quantity,
vif_scaling,
dif_signedness,
match,
display_unit
);
@ -325,12 +351,25 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *
}
else
{
dd->addStringFieldWithExtractor(
name,
info,
properties,
match
);
if (num_lookups > 0)
{
dd->addStringFieldWithExtractorAndLookup(
name,
info,
properties,
match,
lookup
);
}
else
{
dd->addStringFieldWithExtractor(
name,
info,
properties,
match
);
}
}
return XMQ_CONTINUE;
}
@ -339,22 +378,79 @@ XMQProceed DriverDynamic::add_match(XMQDoc *doc, XMQNode *match, DriverDynamic *
{
FieldMatcher *fm = dd->tmp_matcher_;
check_set_measurement_type(xmqGetString(doc, match, "measurement_type"), fm, dd);
if (checked_set_difvifkey(xmqGetString(doc, match, "difvifkey"), fm, dd)) return XMQ_CONTINUE;
check_set_vif_range(xmqGetString(doc, match, "vif_range"), fm, dd);
checked_set_measurement_type(xmqGetString(doc, match, "measurement_type"), fm, dd);
const char *vif_range_s = xmqGetString(doc, match, "vif_range");
checked_set_vif_range(xmqGetString(doc, match, "vif_range"), fm, dd);
if (vif_range_s)
{
VIFRange vif_range = toVIFRange(vif_range_s);
if (vif_range == VIFRange::None)
{
warning("(driver) error unknown measurement type %s\n", vif_range_s);
throw 1;
}
fm->set(vif_range);
checked_set_storagenr_range(xmqGetString(doc, match, "storage_nr"), fm, dd);
xmqForeach(doc, match, "add_combinable", (XMQNodeCallback)add_combinable, dd);
return XMQ_CONTINUE;
}
XMQProceed DriverDynamic::add_combinable(XMQDoc *doc, XMQNode *match, DriverDynamic *dd)
{
FieldMatcher *fm = dd->tmp_matcher_;
checked_add_vif_combinable(xmqGetString(doc, match, "."), fm, dd);
return XMQ_CONTINUE;
}
/**
add_map:
Add a mapping from a value (bits,index,decimal) to a string name.
map {
name = SURGE
info = 'Unexpected increase in pressure in relation to average pressure.'
value = 0x02
test = set
}
*/
XMQProceed DriverDynamic::add_map(XMQDoc *doc, XMQNode *map, DriverDynamic *dd)
{
const char *name = xmqGetString(doc, map, "name");
uint64_t value = checked_value(xmqGetString(doc, map, "value"), dd);
TestBit test_type = checked_test_type(xmqGetString(doc, map, "test"), dd);
dd->tmp_rule_->add(Translate::Map(value, name, test_type));
return XMQ_CONTINUE;
}
/**
add_lookup:
Add a lookup from bits,index or decimal to a sequence of string tokens.
Or fallback to the name (ERROR_FLAGS_8) suffixed by the untranslateable bits.
lookup {
name = ERROR_FLAGS
map_type = BitToString
mask_bits = 0xffff
default_message = OK
map { } map {}
}
*/
XMQProceed DriverDynamic::add_lookup(XMQDoc *doc, XMQNode *lookup, DriverDynamic *dd)
{
const char *name = xmqGetString(doc, lookup, "name");
Translate::MapType map_type = checked_map_type(xmqGetString(doc, lookup, "map_type"), dd);
uint64_t mask_bits = checked_mask_bits(xmqGetString(doc, lookup, "mask_bits"), dd);
const char *default_message = xmqGetString(doc, lookup, "default_message");
Translate::Rule rule = Translate::Rule(name, map_type);
dd->tmp_rule_ = &rule;
rule.set(MaskBits(mask_bits));
rule.set(DefaultMessage(default_message));
xmqForeach(doc, lookup, "map", (XMQNodeCallback)add_map, dd);
dd->tmp_lookup_->add(rule);
return XMQ_CONTINUE;
}
@ -544,12 +640,12 @@ VifScaling check_vif_scaling(const char *vif_scaling_s, DriverDynamic *dd)
warning("(driver) error in %s, bad vif scaling: %s\n",
"%s\n"
"Available vif scalings:\n"
"%s\n"
"Auto\n"
"None\n"
"%s\n",
dd->fileName().c_str(),
vif_scaling_s,
line,
"???",
line);
throw 1;
}
@ -557,6 +653,33 @@ VifScaling check_vif_scaling(const char *vif_scaling_s, DriverDynamic *dd)
return vif_scaling;
}
DifSignedness check_dif_signedness(const char *dif_signedness_s, DriverDynamic *dd)
{
if (!dif_signedness_s)
{
return DifSignedness::Signed;
}
DifSignedness dif_signedness = toDifSignedness(dif_signedness_s);
if (dif_signedness == DifSignedness::Unknown)
{
warning("(driver) error in %s, bad dif signedness: %s\n",
"%s\n"
"Available dif signedness:\n"
"Signed\n"
"Unsigned\n"
"%s\n",
dd->fileName().c_str(),
dif_signedness_s,
line,
line);
throw 1;
}
return dif_signedness;
}
PrintProperties check_print_properties(const char *print_properties_s, DriverDynamic *dd)
{
if (!print_properties_s)
@ -622,7 +745,32 @@ Unit check_display_unit(const char *display_unit_s, DriverDynamic *dd)
return u;
}
void check_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm, DriverDynamic *dd)
bool checked_set_difvifkey(const char *difvifkey_s, FieldMatcher *fm, DriverDynamic *dd)
{
if (!difvifkey_s) return false;
bool invalid_hex = false;
bool hex = isHexStringStrict(difvifkey_s, &invalid_hex);
if (!hex || invalid_hex)
{
warning("(driver) error in %s, bad divfikey: %s\n"
"%s\n"
"Should be all hex.\n"
"%s\n",
dd->fileName().c_str(),
difvifkey_s,
line,
line);
throw 1;
}
fm->set(DifVifKey(difvifkey_s));
return true;
}
void checked_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm, DriverDynamic *dd)
{
if (!measurement_type_s)
{
@ -665,7 +813,7 @@ void check_set_measurement_type(const char *measurement_type_s, FieldMatcher *fm
fm->set(measurement_type);
}
void check_set_vif_range(const char *vif_range_s, FieldMatcher *fm, DriverDynamic *dd)
void checked_set_vif_range(const char *vif_range_s, FieldMatcher *fm, DriverDynamic *dd)
{
if (!vif_range_s)
{
@ -701,3 +849,173 @@ void check_set_vif_range(const char *vif_range_s, FieldMatcher *fm, DriverDynami
fm->set(vif_range);
}
void checked_set_storagenr_range(const char *storagenr_range_s, FieldMatcher *fm, DriverDynamic *dd)
{
if (!storagenr_range_s) return;
auto fields = splitString(storagenr_range_s, ',');
bool ok = isNumber(fields[0]);
if (fields.size() > 1)
{
ok &= isNumber(fields[1]);
}
if (!ok || fields.size() > 2)
{
warning("(driver) error in %s, bad storagenr_range: %s\n"
"%s\n",
dd->fileName().c_str(),
storagenr_range_s,
line);
throw 1;
}
if (fields.size() == 1)
{
fm->set(StorageNr(atoi(fields[0].c_str())));
}
else
{
fm->set(StorageNr(atoi(fields[0].c_str())),
StorageNr(atoi(fields[1].c_str())));
}
}
void checked_add_vif_combinable(const char *vif_combinable_s, FieldMatcher *fm, DriverDynamic *dd)
{
if (!vif_combinable_s) return;
VIFCombinable vif_combinable = toVIFCombinable(vif_combinable_s);
if (vif_combinable == VIFCombinable::None)
{
warning("(driver) error in %s, bad vif_combinable: %s\n"
"%s\n"
"Available vif combinables:\n"
"%s\n"
"%s\n",
dd->fileName().c_str(),
vif_combinable_s,
line,
availableVIFCombinables().c_str(),
line);
throw 1;
}
fm->add(vif_combinable);
}
Translate::MapType checked_map_type(const char *map_type_s, DriverDynamic *dd)
{
if (!map_type_s)
{
warning("(driver) error in %s, cannot find: driver/field/lookup/map_type\n"
"%s\n"
"Remember to add for example: lookup { map_type = BitToString ... }\n"
"Available map types:\n"
"BitToString\n"
"IndexToString\n"
"DecimalsToString\n"
"%s\n",
dd->fileName().c_str(),
line,
line);
throw 1;
}
Translate::MapType map_type = toMapType(map_type_s);
if (map_type == Translate::MapType::Unknown)
{
warning("(driver) error in %s, bad map_type: %s\n"
"%s\n"
"Available map types:\n"
"BitToString\n"
"IndexToString\n"
"DecimalToString\n"
"%s\n",
dd->fileName().c_str(),
map_type_s,
line,
line);
throw 1;
}
return map_type;
}
uint64_t checked_mask_bits(const char *mask_bits_s, DriverDynamic *dd)
{
if (!mask_bits_s)
{
warning("(driver) error in %s, cannot find: driver/field/lookup/mask_bitse\n"
"%s\n"
"Remember to add for example: lookup { mask_bits = 0x00ff ... }\n"
"%s\n",
dd->fileName().c_str(),
line,
line);
throw 1;
}
uint64_t mask = strtol(mask_bits_s, NULL, 16);
return mask;
}
uint64_t checked_value(const char *value_s, DriverDynamic *dd)
{
if (!value_s)
{
warning("(driver) error in %s, cannot find: driver/field/lookup/map/value\n"
"%s\n"
"Remember to add for example: lookup { map { ... value = 0x01 ... }}\n"
"%s\n",
dd->fileName().c_str(),
line,
line);
throw 1;
}
uint64_t value = strtol(value_s, NULL, 16);
return value;
}
TestBit checked_test_type(const char *test_s, DriverDynamic *dd)
{
if (!test_s)
{
warning("(driver) error in %s, cannot find: driver/field/lookup/map/test\n"
"%s\n"
"Remember to add for example: lookup { map { test = Set } }\n"
"Available test types:\n"
"Set\n"
"NotSet\n"
"%s\n",
dd->fileName().c_str(),
line,
line);
throw 1;
}
TestBit test_type = toTestBit(test_s);
if (test_type == TestBit::Unknown)
{
warning("(driver) error in %s, bad test: %s\n"
"%s\n"
"Available test types:\n"
"Set\n"
"NotSet\n"
"%s\n",
dd->fileName().c_str(),
test_s,
line,
line);
throw 1;
}
return test_type;
}

Wyświetl plik

@ -1,5 +1,5 @@
/*
Copyright (C) 2023 Fredrik Öhrström (gpl-3.0-or-later)
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
@ -29,6 +29,10 @@ struct DriverDynamic : public virtual MeterCommonImplementation
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_; }
@ -36,6 +40,8 @@ private:
string file_name_;
FieldMatcher *tmp_matcher_;
Translate::Lookup *tmp_lookup_;
Translate::Rule *tmp_rule_;
};
#endif

Wyświetl plik

@ -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)

Wyświetl plik

@ -47,7 +47,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)
@ -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)

Wyświetl plik

@ -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",
{

Wyświetl plik

@ -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)

Wyświetl plik

@ -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"))
);

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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"))
);

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -49,7 +49,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -67,7 +67,7 @@ namespace
"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)

Wyświetl plik

@ -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))

Wyświetl plik

@ -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),
"",
{

Wyświetl plik

@ -70,7 +70,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger,
AutoMask,
"OK",
@ -85,7 +85,7 @@ namespace
},
{
"ERROR_FLAGS_SINGLE_PHASE",
Translate::Type::BitToString,
Translate::MapType::BitToString,
TriggerBits(0x01020000),
AutoMask,
"OK",
@ -99,7 +99,7 @@ namespace
},
{
"ERROR_FLAGS_THREE_PHASE",
Translate::Type::BitToString,
Translate::MapType::BitToString,
TriggerBits(0x01010000),
AutoMask,
"OK",
@ -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"))
);

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -44,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)
@ -55,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),

Wyświetl plik

@ -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)
@ -128,7 +128,7 @@ namespace
"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)
@ -140,7 +140,7 @@ namespace
"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),

Plik diff jest za duży Load Diff

Wyświetl plik

@ -60,7 +60,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffff),
"OK",
{
@ -75,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)
@ -102,7 +102,7 @@ namespace
{
{
"WOOTA",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffffff),
"",
{
@ -122,7 +122,7 @@ namespace
{
{
"WOOTB",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"",
{
@ -156,4 +156,3 @@ namespace
// 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

Wyświetl plik

@ -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)
@ -74,7 +74,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffffff),
"OK",
{
@ -120,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)
@ -131,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)
@ -142,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)
@ -153,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)
@ -164,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)
@ -175,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)
@ -186,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)
@ -197,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)
@ -208,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);
@ -218,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);
@ -237,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)
@ -249,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)
@ -271,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)
@ -314,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
@ -354,3 +354,8 @@ namespace
// 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

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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"))
);

Wyświetl plik

@ -40,7 +40,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 ,"LOW_BATTERY", TestBit::Set))));
@ -56,7 +56,7 @@ namespace
"Number of total routed messages since power up",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Dimensionless)
@ -67,7 +67,7 @@ namespace
"Used router slots (maximum 936)",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Dimensionless)
@ -92,7 +92,7 @@ namespace
.set(VIFRange::Dimensionless)
.set(SubUnitNr(2)),
Translate::Lookup()
.add(Translate::Rule("INPUT_BITS", Translate::Type::IndexToString)
.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))
@ -103,7 +103,7 @@ namespace
"Seconds to mode change (Listen -> Sleep or Sleep -> Listen). Maximum 32767 seconds",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Dimensionless)
@ -115,7 +115,7 @@ namespace
"Value on parameter 'Listen timer'",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Dimensionless)
@ -127,7 +127,7 @@ namespace
"Value on parameter 'Pause timer'",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Dimensionless)
@ -143,7 +143,7 @@ namespace
.set(VIFRange::Dimensionless)
.set(StorageNr(3)),
Translate::Lookup()
.add(Translate::Rule("INPUT_BITS", Translate::Type::BitToString)
.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))
@ -159,7 +159,7 @@ namespace
"Value on parameter 'Start time', shown as minusted after midnight (-1=Not used)",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Dimensionless)
@ -180,7 +180,7 @@ namespace
"Battery voltage.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Voltage,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Voltage)

Wyświetl plik

@ -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)

Wyświetl plik

@ -39,7 +39,7 @@ namespace
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)

Wyświetl plik

@ -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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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",
{
@ -212,8 +212,8 @@ namespace
// 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|

Wyświetl plik

@ -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)

Wyświetl plik

@ -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),
"",
{

Wyświetl plik

@ -47,7 +47,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -62,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)
@ -73,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)

Wyświetl plik

@ -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"))
);

Wyświetl plik

@ -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)

Wyświetl plik

@ -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)

Wyświetl plik

@ -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,7 +172,7 @@ 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)

Wyświetl plik

@ -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)
@ -97,7 +97,7 @@ namespace
"Percentage of battery remaining.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("01FD74")),
Unit::PERCENTAGE
@ -118,5 +118,5 @@ namespace
// 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": 555.36,"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}
// {"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

Wyświetl plik

@ -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)

Wyświetl plik

@ -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();

Wyświetl plik

@ -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)

Wyświetl plik

@ -49,7 +49,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -73,7 +73,7 @@ namespace
"Number of times the smoke alarm has triggered.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Unsigned,
FieldMatcher::build()
.set(DifVifKey("81037C034C4123"))
);
@ -102,7 +102,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(DifVifKey("81027C03495523"))
);
@ -112,7 +112,7 @@ namespace
"Transmission counter?",
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
VifScaling::None, DifSignedness::Unsigned,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AccessNumber)
@ -132,7 +132,7 @@ namespace
"What does this mean?",
DEFAULT_PRINT_PROPERTIES,
Quantity::Time,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("02FDAC7E"))
);

Wyświetl plik

@ -53,7 +53,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffffff),
"OK",
{
@ -69,7 +69,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)
@ -81,7 +81,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)
@ -93,7 +93,7 @@ namespace
"The current power consumption.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -114,7 +114,7 @@ namespace
"The heating energy consumption recorded at the end of the previous billing period.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -127,7 +127,7 @@ namespace
"The cooling energy consumption recorded at the end of the previous billing period.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)

Wyświetl plik

@ -65,7 +65,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 +77,7 @@ namespace
"The due date for billing date.",
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)
@ -90,7 +90,7 @@ namespace
"The water consumption at the 17 due date.",
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 due date for billing date.",
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)
@ -115,7 +115,7 @@ namespace
"Media volume flow when duration exceeds lower last.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Flow,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::VolumeFlow)
@ -127,7 +127,7 @@ namespace
"The date the error occurred at. If no error, reads 2127-15-31 (FFFF).",
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::AtError)
.set(VIFRange::Date),

Wyświetl plik

@ -47,7 +47,7 @@ namespace
"The current temperature.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::ExternalTemperature)
@ -58,7 +58,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)
@ -70,7 +70,7 @@ namespace
"The average temperature over the last 24 hours.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::ExternalTemperature)
@ -82,7 +82,7 @@ namespace
"The maximum temperature over the last hour.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Maximum)
.set(VIFRange::ExternalTemperature)
@ -93,7 +93,7 @@ namespace
"The maximum temperature over the last 24 hours.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Maximum)
.set(VIFRange::ExternalTemperature)
@ -105,7 +105,7 @@ namespace
"The minimum temperature over the last hour.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Minimum)
.set(VIFRange::ExternalTemperature)
@ -116,7 +116,7 @@ namespace
"The minimum temperature over the last 24 hours.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Minimum)
.set(VIFRange::ExternalTemperature)
@ -128,7 +128,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)
@ -139,7 +139,7 @@ namespace
"The average relative humidity over the last hour.",
DEFAULT_PRINT_PROPERTIES,
Quantity::RelativeHumidity,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::RelativeHumidity)
@ -151,7 +151,7 @@ namespace
"The average relative 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)
@ -163,7 +163,7 @@ namespace
"The maximum relative humidity over the last hour.",
DEFAULT_PRINT_PROPERTIES,
Quantity::RelativeHumidity,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Maximum)
.set(VIFRange::RelativeHumidity)
@ -174,7 +174,7 @@ namespace
"The maximum relative humidity over the last 24 hours.",
DEFAULT_PRINT_PROPERTIES,
Quantity::RelativeHumidity,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Maximum)
.set(VIFRange::RelativeHumidity)
@ -186,7 +186,7 @@ namespace
"The minimum relative humidity over the last hour.",
DEFAULT_PRINT_PROPERTIES,
Quantity::RelativeHumidity,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Minimum)
.set(VIFRange::RelativeHumidity)
@ -197,7 +197,7 @@ namespace
"The minimum relative humidity over the last 24 hours.",
DEFAULT_PRINT_PROPERTIES,
Quantity::RelativeHumidity,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Minimum)
.set(VIFRange::RelativeHumidity)
@ -209,7 +209,7 @@ namespace
"The meters date time.",
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::DateTime)

Wyświetl plik

@ -43,7 +43,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)

Wyświetl plik

@ -51,7 +51,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)
@ -62,7 +62,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)
@ -73,7 +73,7 @@ namespace
"The maximum power consumption over ?period?.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Maximum)
.set(VIFRange::AnyPowerVIF)
@ -84,7 +84,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)
@ -95,7 +95,7 @@ namespace
"The maximum forward flow of water over a ?period?.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Flow,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Maximum)
.set(VIFRange::VolumeFlow)
@ -106,7 +106,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)
@ -117,7 +117,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)
@ -128,7 +128,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)
@ -139,7 +139,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)
@ -155,7 +155,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xff),
"OK",
{
@ -188,7 +188,7 @@ namespace
"The energy consumption at the last billing period date.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -205,7 +205,7 @@ namespace
info,
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -220,8 +220,14 @@ namespace
// {"media":"heat","meter":"sensostar","name":"Heat","id":"20480057","meter_timestamp":"2022-04-28 13:44","total_kwh":0,"power_kw":0,"power_max_kw":0,"flow_water_m3h":0,"flow_water_max_m3h":0,"forward_c":20,"return_c":21,"difference_c":-0.38,"total_water_m3":0,"current_status":"ERROR_FLOW_MEASUREMENT_SYSTEM_ERROR","reporting_date":"2000-00-00","energy_consumption_at_reporting_date_kwh":0,"consumption_1_months_ago_kwh":0,"timestamp":"1111-11-11T11:11:11Z"}
// |Heat;20480057;0;0;ERROR_FLOW_MEASUREMENT_SYSTEM_ERROR;2000-00-00;0;1111-11-11 11:11.11
// Test: WMZ sensostar 02752560 NOKEY
// Comment: from "Sensostar U"
//Test: WMZ sensostar 02752560 NOKEY
//Comment: from "Sensostar U"
//telegram=a444c5146025750200047ac20000202f2f046d2e26c62a040643160000041310f0050001fd1700426cbf2c4406570e00008401061f160000840206f6150000840306f5150000840406f3150000840506ea150000840606bf1500008407065214000084080692120000840906c5100000840a06570e0000840b06ca0b0000840c06da090000840d06ca080000840e06c8080000840f06c608000003fd0c05010002fd0b2111
//{"media":"heat","meter":"sensostar","name":"WMZ","id":"02752560","meter_timestamp":"2022-10-06 06:46","total_kwh":5699,"total_water_m3":389.136,"current_status":"OK","reporting_date":"2021-12-31","energy_consumption_at_reporting_date_kwh":3671,"consumption_1_months_ago_kwh":5663,"consumption_2_months_ago_kwh":5622,"consumption_3_months_ago_kwh":5621,"consumption_4_months_ago_kwh":5619,"consumption_5_months_ago_kwh":5610,"consumption_6_months_ago_kwh":5567,"consumption_7_months_ago_kwh":5202,"consumption_8_months_ago_kwh":4754,"consumption_9_months_ago_kwh":4293,"consumption_10_months_ago_kwh":3671,"consumption_11_months_ago_kwh":3018,"consumption_12_months_ago_kwh":2522,"consumption_13_months_ago_kwh":2250,"consumption_14_months_ago_kwh":2248,"consumption_15_months_ago_kwh":2246,"timestamp":"1111-11-11 11:11.11"}
//WMZ;02752560;5699;389.136000;OK;1111-11-11 11:11.11
// Test: ABC sensostar 21750444 NOKEY
// Comment: Test negative flow values
// telegram=4944C5144404752100047AC1000020_2F2F046D142D073404068847000001FD170004138E8A4000043BF7FFFFFF042B00000000025B3E00025F360002612F0303FD0C05010002FD0B2011
// {"current_status": "OK","difference_c": 8.15,"flow_water_m3h": -0.009,"forward_c": 62,"id": "21750444","media": "heat","meter": "sensostar","meter_timestamp": "2024-04-07 13:20","name": "ABC","power_kw": 0,"return_c": 54,"timestamp": "1111-11-11T11:11:11Z","total_kwh": 18312,"total_water_m3": 4229.774}
// |ABC;21750444;18312;4229.774;OK;null;null;1111-11-11 11:11.11

Wyświetl plik

@ -51,7 +51,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(0x0000))
.set(DefaultMessage("OK"))
));
@ -61,7 +61,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)
@ -72,7 +72,7 @@ namespace
"The total heat 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)
@ -84,7 +84,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)
@ -95,7 +95,7 @@ namespace
"The total heating media volume recorded by this meter on tariff 2.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Volume)
@ -107,7 +107,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)
@ -118,7 +118,7 @@ namespace
"The current power consumption.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::PowerW)
@ -129,7 +129,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)
@ -140,7 +140,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)
@ -151,7 +151,7 @@ namespace
"The current return heat media temperature.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::TemperatureDifference)
@ -162,7 +162,7 @@ namespace
"The total heat energy consumption recorded by this meter at the end of the previous billing period.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -174,7 +174,7 @@ namespace
"The total heating media volume recorded by this meter 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)
@ -186,7 +186,7 @@ namespace
"The last billing period end date.",
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)

Wyświetl plik

@ -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 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)
@ -71,7 +71,7 @@ namespace
"The total volume recorded by this meter.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyVolumeVIF)
@ -82,7 +82,7 @@ namespace
"The total cooling volume recorded by this meter.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyVolumeVIF)
@ -94,7 +94,7 @@ namespace
"The current flow.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Flow,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::VolumeFlow)
@ -105,7 +105,7 @@ namespace
"The power.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyPowerVIF)
@ -116,7 +116,7 @@ namespace
"The flow temperature.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::FlowTemperature)
@ -127,7 +127,7 @@ namespace
"The return temperature.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::ReturnTemperature)
@ -138,7 +138,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)
@ -149,7 +149,7 @@ namespace
"How long the meter has been in an error state and not collected data.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Time,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::OperatingTime)
@ -161,7 +161,7 @@ namespace
"The total 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)
@ -173,7 +173,7 @@ namespace
"The total cooling 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)
@ -186,7 +186,7 @@ namespace
"The last billing set date.",
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)

Wyświetl plik

@ -43,7 +43,7 @@ namespace
"The current heat cost allocation for this meter.",
DEFAULT_PRINT_PROPERTIES,
Quantity::HCA,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::HeatCostAllocation)
@ -64,7 +64,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)
@ -76,7 +76,7 @@ namespace
"The current temperature of the heating element.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::FlowTemperature)
@ -87,7 +87,7 @@ namespace
"The current room temperature.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::ExternalTemperature)
@ -98,7 +98,7 @@ namespace
"The maximum temperature so far during this billing period.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Maximum)
.set(VIFRange::FlowTemperature)
@ -110,7 +110,7 @@ namespace
"The maximum temperature during the previous billing period.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Maximum)
.set(VIFRange::FlowTemperature)

Wyświetl plik

@ -48,7 +48,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(0x000f))
.set(DefaultMessage("OK"))
));

Wyświetl plik

@ -49,8 +49,8 @@ namespace
di.setName("topaseskr");
di.setDefaultFields(
"name,id,total_m3,temperature_c,current_flow_m3h,volume_year_period_m3,"
"reverse_volume_year_period_m3,meter_year_period_start_date,volume_month_period_m3,"
"meter_month_period_start_datetime,timestamp");
"reverse_volume_year_period_m3,meter_year_period_end_date,volume_month_period_m3,"
"meter_month_period_end_datetime,timestamp");
di.setMeterType(MeterType::WaterMeter);
di.addLinkMode(LinkMode::T1);
di.addDetection(MANUFACTURER_AMT, 0x06, 0xf1);
@ -67,7 +67,7 @@ namespace
"Current water temperature recorded by this meter.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::FlowTemperature));
@ -77,7 +77,7 @@ namespace
"The current water flow.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Flow,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::VolumeFlow));
@ -87,7 +87,7 @@ namespace
"Volume up to end of last year-period.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Volume)
@ -99,7 +99,7 @@ namespace
"Reverse volume in this year-period (?)",
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Volume)
@ -109,8 +109,8 @@ namespace
addStringFieldWithExtractor(
"meter_year_period_start_date",
"Meter date for year-period start.",
"meter_year_period_end_date",
"Meter date for year-period end.",
DEFAULT_PRINT_PROPERTIES,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
@ -123,7 +123,7 @@ namespace
"Volume up to end of last month-period.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Volume)
@ -131,8 +131,8 @@ namespace
);
addStringFieldWithExtractor(
"meter_month_period_start_datetime",
"Meter timestamp for month-period start.",
"meter_month_period_end_datetime",
"Meter timestamp for month-period end.",
DEFAULT_PRINT_PROPERTIES,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
@ -145,7 +145,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),
@ -155,10 +155,10 @@ namespace
// Test: Witer topaseskr 78563412 NOKEY
// 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: Woter topaseskr 69190253 NOKEY
// telegram=|4E44B40553021969F1077A0C0040052F2F_01FD08800C13914544004C1393673500CC101300000000CC201393673500426CDF2C0B3B0100F002FD747912025AAE00C4016D3B17FF25CC011325584100|
// {"access_counter": 128,"battery_y": 12.947562,"current_flow_m3h": -0.001,"id": "69190253","media": "water","meter": "topaseskr","meter_month_period_start_datetime": "2023-05-31 23:59","meter_year_period_start_date": "2022-12-31","name": "Woter","reverse_volume_year_period_m3": 0,"temperature_c": 17.4,"timestamp": "1111-11-11T11:11:11Z","total_m3": 444.591,"volume_month_period_m3": 415.825,"volume_year_period_m3": 356.793}
// {"access_counter": 128,"battery_y": 12.947562,"current_flow_m3h": -0.001,"id": "69190253","media": "water","meter": "topaseskr","meter_month_period_end_datetime": "2023-05-31 23:59","meter_year_period_end_date": "2022-12-31","name": "Woter","reverse_volume_year_period_m3": 0,"temperature_c": 17.4,"timestamp": "1111-11-11T11:11:11Z","total_m3": 444.591,"volume_month_period_m3": 415.825,"volume_year_period_m3": 356.793}
// |Woter;69190253;444.591;17.4;-0.001;356.793;0;2022-12-31;415.825;2023-05-31 23:59;1111-11-11 11:11.11

Wyświetl plik

@ -42,7 +42,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)
@ -53,7 +53,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)
@ -64,7 +64,7 @@ namespace
"The current power consumption.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Power,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::PowerW)
@ -75,7 +75,7 @@ namespace
"The current heat media volume flow.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Flow,
VifScaling::AutoSigned,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::VolumeFlow)
@ -86,7 +86,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)
@ -97,7 +97,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)
@ -114,7 +114,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{

Wyświetl plik

@ -40,7 +40,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)
@ -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)
@ -68,7 +68,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffffff),
"OK",
{
@ -92,7 +92,7 @@ namespace
"The total backward water volume recorded by this meter.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(DifVifKey("04933C"))
);

Wyświetl plik

@ -49,7 +49,7 @@ namespace
{
{
"STATUS_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -68,7 +68,7 @@ namespace
{
{
"OTHER_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xff),
"",
{
@ -92,7 +92,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)
@ -114,7 +114,7 @@ namespace
"The total gas consumption recorded by this meter 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)

Wyświetl plik

@ -44,7 +44,7 @@ namespace
"Total energy consumption at the end of the year",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -56,7 +56,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)

Wyświetl plik

@ -42,7 +42,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)
@ -53,7 +53,7 @@ namespace
"The total energy consumption recorded when?",
DEFAULT_PRINT_PROPERTIES,
Quantity::Energy,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyEnergyVIF)
@ -65,7 +65,7 @@ namespace
"The last billing old date?",
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)
@ -77,7 +77,7 @@ namespace
"The total energy consumption recorded by this meter at the due date.",
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 last billing set date.",
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)

Wyświetl plik

@ -52,7 +52,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -75,7 +75,7 @@ namespace
"Device date time.",
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::DateTime)
@ -86,7 +86,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)
@ -97,7 +97,7 @@ namespace
"The total backward water volume recorded by this meter.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AnyVolumeVIF)
@ -114,7 +114,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -155,7 +155,7 @@ namespace
"The battery voltage.",
DEFAULT_PRINT_PROPERTIES,
Quantity::Voltage,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Voltage)
@ -166,7 +166,7 @@ namespace
"The most recent billing period date.",
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)
@ -179,7 +179,7 @@ namespace
"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)
@ -191,7 +191,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)

Wyświetl plik

@ -48,7 +48,7 @@ namespace
{
{
"ERROR_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger, MaskBits(0xffff),
"OK",
{
@ -62,7 +62,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)

Wyświetl plik

@ -43,7 +43,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 +54,7 @@ namespace
"The most recent billing period date.",
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
VifScaling::Auto, DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)
@ -67,7 +67,7 @@ namespace
"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)

Wyświetl plik

@ -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)
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
@ -62,6 +62,17 @@ LIST_OF_VIF_RANGES
return VIFRange::None;
}
VIFCombinable toVIFCombinable(const char *s)
{
if (!strcmp(s, "None")) return VIFCombinable::None;
if (!strcmp(s, "Any")) return VIFCombinable::Any;
#define X(name,from,to) if (!strcmp(s, #name)) return VIFCombinable::name;
LIST_OF_VIF_COMBINABLES
#undef X
return VIFCombinable::None;
}
const char *toString(VIFCombinable v)
{
switch (v) {
@ -124,7 +135,8 @@ bool isInsideVIFRange(Vif vif, VIFRange vif_range)
return
isInsideVIFRange(vif, VIFRange::EnergyWh) ||
isInsideVIFRange(vif, VIFRange::EnergyMJ) ||
isInsideVIFRange(vif, VIFRange::EnergyMWh);
isInsideVIFRange(vif, VIFRange::EnergyMWh) ||
isInsideVIFRange(vif, VIFRange::EnergyGJ);
}
if (vif_range == VIFRange::AnyPowerVIF)
{
@ -302,9 +314,12 @@ bool parseDV(Telegram *t,
int storage_nr = lsb_of_storage_nr;
bool has_another_dife = (dif & 0x80) == 0x80;
int num_dife = 0;
while (has_another_dife)
{
num_dife++;
if (num_dife > 10) { debug("(dvparser) warning: too many dife found!\n"); break; }
if (*format == format_end) { debug("(dvparser) warning: unexpected end of data (dife expected)\n"); break; }
uchar dife = **format;
@ -390,8 +405,13 @@ bool parseDV(Telegram *t,
// Do we have another vife byte? We better have one, if extension_vif is true.
bool has_another_vife = (vif & 0x80) == 0x80;
int num_vife = 0;
while (has_another_vife)
{
num_vife++;
if (num_vife > 10) { debug("(dvparser) warning: too many vife found!\n"); break; }
if (*format == format_end) { debug("(dvparser) warning: unexpected end of data (vife expected)\n"); break; }
uchar vife = **format;
@ -437,7 +457,7 @@ bool parseDV(Telegram *t,
if (data_has_difvifs)
{
t->addExplanationAndIncrementPos(*format, 1, KindOfData::PROTOCOL, Understanding::FULL,
"%02X combinable extension vife", vife);
"%02X combinable extension vife (%s)", vife, toString(vc));
}
}
else
@ -743,7 +763,7 @@ bool extractDVdouble(map<string,pair<int,DVEntry>> *dv_entries,
int *offset,
double *value,
bool auto_scale,
bool assume_signed)
bool force_unsigned)
{
if ((*dv_entries).count(key) == 0) {
verbose("(dvparser) warning: cannot extract double from non-existant key \"%s\"\n", key.c_str());
@ -761,7 +781,7 @@ bool extractDVdouble(map<string,pair<int,DVEntry>> *dv_entries,
return false;
}
return p.second.extractDouble(value, auto_scale, assume_signed);
return p.second.extractDouble(value, auto_scale, force_unsigned);
}
bool checkSizeHex(size_t expected_len, DifVifKey &dvk, string &v)
@ -782,7 +802,7 @@ bool is_all_F(string &v)
return true;
}
bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed)
bool DVEntry::extractDouble(double *out, bool auto_scale, bool force_unsigned)
{
int t = dif_vif_key.dif() & 0xf;
if (t == 0x0 ||
@ -811,17 +831,17 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed)
if (!checkSizeHex(2, dif_vif_key, value)) return false;
assert(v.size() == 1);
raw = v[0];
if (assume_signed && (raw & (uint64_t)0x80UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<8; }
if (!force_unsigned && (raw & (uint64_t)0x80UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<8; }
} else if (t == 0x2) {
if (!checkSizeHex(4, dif_vif_key, value)) return false;
assert(v.size() == 2);
raw = v[1]*256 + v[0];
if (assume_signed && (raw & (uint64_t)0x8000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<16; }
if (!force_unsigned && (raw & (uint64_t)0x8000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<16; }
} else if (t == 0x3) {
if (!checkSizeHex(6, dif_vif_key, value)) return false;
assert(v.size() == 3);
raw = v[2]*256*256 + v[1]*256 + v[0];
if (assume_signed && (raw & (uint64_t)0x800000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<24; }
if (!force_unsigned && (raw & (uint64_t)0x800000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<24; }
} else if (t == 0x4) {
if (!checkSizeHex(8, dif_vif_key, value)) return false;
assert(v.size() == 4);
@ -829,7 +849,7 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed)
+ ((unsigned int)v[2])*256*256
+ ((unsigned int)v[1])*256
+ ((unsigned int)v[0]);
if (assume_signed && (raw & (uint64_t)0x80000000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<32; }
if (!force_unsigned && (raw & (uint64_t)0x80000000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<32; }
} else if (t == 0x6) {
if (!checkSizeHex(12, dif_vif_key, value)) return false;
assert(v.size() == 6);
@ -839,7 +859,7 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed)
+ ((uint64_t)v[2])*256*256
+ ((uint64_t)v[1])*256
+ ((uint64_t)v[0]);
if (assume_signed && (raw & (uint64_t)0x800000000000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<48; }
if (!force_unsigned && (raw & (uint64_t)0x800000000000UL) != 0) { negate = true; negate_mask = ~((uint64_t)0)<<48; }
} else if (t == 0x7) {
if (!checkSizeHex(16, dif_vif_key, value)) return false;
assert(v.size() == 8);
@ -851,7 +871,7 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed)
+ ((uint64_t)v[2])*256*256
+ ((uint64_t)v[1])*256
+ ((uint64_t)v[0]);
if (assume_signed && (raw & (uint64_t)0x8000000000000000UL) != 0) { negate = true; negate_mask = 0; }
if (!force_unsigned && (raw & (uint64_t)0x8000000000000000UL) != 0) { negate = true; negate_mask = 0; }
}
double scale = 1.0;
double draw = (double)raw;
@ -869,8 +889,8 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed)
t == 0xC || // 8 digit BCD
t == 0xE) // 12 digit BCD
{
// Signed BCD values are always visible in bcd! Top nybble is f. We can force assume_signed to true.
assume_signed = true;
// Negative BCD values are always visible in bcd. I.e. they are always signed.
// Ignore assumption on signedness.
// 74140000 -> 00001474
string& v = value;
uint64_t raw = 0;
@ -883,29 +903,29 @@ bool DVEntry::extractDouble(double *out, bool auto_scale, bool assume_signed)
}
if (t == 0x9) {
if (!checkSizeHex(2, dif_vif_key, v)) return false;
if (assume_signed && v[0] == 'F') { negate = true; v[0] = '0'; }
if (v[0] == 'F') { negate = true; v[0] = '0'; }
raw = (v[0]-'0')*10 + (v[1]-'0');
} else if (t == 0xA) {
if (!checkSizeHex(4, dif_vif_key, v)) return false;
if (assume_signed && v[2] == 'F') { negate = true; v[2] = '0'; }
if (v[2] == 'F') { negate = true; v[2] = '0'; }
raw = (v[2]-'0')*10*10*10 + (v[3]-'0')*10*10
+ (v[0]-'0')*10 + (v[1]-'0');
} else if (t == 0xB) {
if (!checkSizeHex(6, dif_vif_key, v)) return false;
if (assume_signed && v[4] == 'F') { negate = true; v[4] = '0'; }
if (v[4] == 'F') { negate = true; v[4] = '0'; }
raw = (v[4]-'0')*10*10*10*10*10 + (v[5]-'0')*10*10*10*10
+ (v[2]-'0')*10*10*10 + (v[3]-'0')*10*10
+ (v[0]-'0')*10 + (v[1]-'0');
} else if (t == 0xC) {
if (!checkSizeHex(8, dif_vif_key, v)) return false;
if (assume_signed && v[6] == 'F') { negate = true; v[6] = '0'; }
if (v[6] == 'F') { negate = true; v[6] = '0'; }
raw = (v[6]-'0')*10*10*10*10*10*10*10 + (v[7]-'0')*10*10*10*10*10*10
+ (v[4]-'0')*10*10*10*10*10 + (v[5]-'0')*10*10*10*10
+ (v[2]-'0')*10*10*10 + (v[3]-'0')*10*10
+ (v[0]-'0')*10 + (v[1]-'0');
} else if (t == 0xE) {
if (!checkSizeHex(12, dif_vif_key, v)) return false;
if (assume_signed && v[10] == 'F') { negate = true; v[10] = '0'; }
if (v[10] == 'F') { negate = true; v[10] = '0'; }
raw =(v[10]-'0')*10*10*10*10*10*10*10*10*10*10*10 + (v[11]-'0')*10*10*10*10*10*10*10*10*10*10
+ (v[8]-'0')*10*10*10*10*10*10*10*10*10 + (v[9]-'0')*10*10*10*10*10*10*10*10
+ (v[6]-'0')*10*10*10*10*10*10*10 + (v[7]-'0')*10*10*10*10*10*10
@ -1299,13 +1319,16 @@ bool FieldMatcher::matches(DVEntry &dv_entry)
}
// Test ranges and types.
bool b =
(!match_vif_range || isInsideVIFRange(dv_entry.vif, vif_range)) &&
(!match_vif_raw || dv_entry.vif == vif_raw) &&
(!match_measurement_type || dv_entry.measurement_type == measurement_type) &&
(!match_storage_nr || (dv_entry.storage_nr >= storage_nr_from && dv_entry.storage_nr <= storage_nr_to)) &&
(!match_tariff_nr || (dv_entry.tariff_nr >= tariff_nr_from && dv_entry.tariff_nr <= tariff_nr_to)) &&
(!match_subunit_nr || (dv_entry.subunit_nr >= subunit_nr_from && dv_entry.subunit_nr <= subunit_nr_to));
bool range = (!match_vif_range || isInsideVIFRange(dv_entry.vif, vif_range));
bool raw = (!match_vif_raw || dv_entry.vif == vif_raw);
bool type = (!match_measurement_type || dv_entry.measurement_type == measurement_type);
bool storage = (!match_storage_nr || (dv_entry.storage_nr >= storage_nr_from && dv_entry.storage_nr <= storage_nr_to));
bool tariff = (!match_tariff_nr || (dv_entry.tariff_nr >= tariff_nr_from && dv_entry.tariff_nr <= tariff_nr_to));
bool subunit = (!match_subunit_nr || (dv_entry.subunit_nr >= subunit_nr_from && dv_entry.subunit_nr <= subunit_nr_to));
//printf("Match? range=%d raw=%d type=%d storage=%d tariff=%d subunit=%d \n", range, raw, type, storage, tariff, subunit);
bool b = range & raw & type & storage & tariff & subunit;
if (!b) return false;
@ -1501,3 +1524,18 @@ LIST_OF_VIF_RANGES
available_vif_ranges_.pop_back();
return available_vif_ranges_;
}
string available_vif_combinables_;
const string &availableVIFCombinables()
{
if (available_vif_combinables_ != "") return available_vif_combinables_;
#define X(n,from,to) available_vif_combinables_ += string(#n) + "\n";
LIST_OF_VIF_COMBINABLES
#undef X
// Remove last newline
available_vif_combinables_.pop_back();
return available_vif_combinables_;
}

Wyświetl plik

@ -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)
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,7 +39,7 @@
X(ExternalTemperature,0x64,0x67, Quantity::Temperature, Unit::C) \
X(Pressure,0x68,0x6B, Quantity::Pressure, Unit::BAR) \
X(HeatCostAllocation,0x6E,0x6E, Quantity::HCA, Unit::HCA) \
X(Date,0x6C,0x6C, Quantity::PointInTime, Unit::DateTimeLT) \
X(Date,0x6C,0x6C, Quantity::PointInTime, Unit::DateLT) \
X(DateTime,0x6D,0x6D, Quantity::PointInTime, Unit::DateTimeLT) \
X(EnergyMJ,0x08,0x0F, Quantity::Energy, Unit::MJ) \
X(EnergyWh,0x00,0x07, Quantity::Energy, Unit::KWH) \
@ -48,6 +48,7 @@
X(FabricationNo,0x78,0x78, Quantity::Text, Unit::TXT) \
X(EnhancedIdentification,0x79,0x79, Quantity::Text, Unit::TXT) \
X(EnergyMWh,0x7B00,0x7B01, Quantity::Energy, Unit::KWH) \
X(EnergyGJ,0x7B09,0x7B0A, Quantity::Energy, Unit::MJ) \
X(RelativeHumidity,0x7B1A,0x7B1B, Quantity::RH, Unit::RH) \
X(AccessNumber,0x7D08,0x7D08, Quantity::Counter, Unit::COUNTER) \
X(Medium,0x7D09,0x7D09, Quantity::Text, Unit::TXT) \
@ -208,6 +209,7 @@ struct VIFCombinableRaw {
uint16_t value;
};
VIFCombinable toVIFCombinable(const char *s);
VIFCombinable toVIFCombinable(int i);
const char *toString(VIFCombinable v);
@ -380,7 +382,7 @@ struct DVEntry
{
}
bool extractDouble(double *out, bool auto_scale, bool assume_signed);
bool extractDouble(double *out, bool auto_scale, bool force_unsigned);
bool extractLong(uint64_t *out);
bool extractDate(struct tm *out);
bool extractReadableString(std::string *out);
@ -560,7 +562,7 @@ bool extractDVdouble(std::map<std::string,std::pair<int,DVEntry>> *values,
int *offset,
double *value,
bool auto_scale = true,
bool assume_signed = false);
bool force_unsigned = false);
// Extract a value without scaling. Works for 8bits to 64 bits, binary and bcd.
bool extractDVlong(std::map<std::string,std::pair<int,DVEntry>> *values,
@ -588,5 +590,6 @@ bool extractDVdate(std::map<std::string,std::pair<int,DVEntry>> *values,
const std::string &availableVIFRanges();
const std::string &availableVIFCombinables();
#endif

Wyświetl plik

@ -15,12 +15,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Generated 2024-02-12_01:46
// Generated 2024-04-04_20:51
BuiltinDriver builtins_[] =
{
{ "elster", "driver{name=elster meter_type=GasMeter default_fields=name,id,total_m3,timestamp detect{mvt=ELS,81,03}use=actuality_duration_s field{name=total quantity=Volume match{measurement_type=Instantaneous vif_range=Volume}about{de='Der Gesamtwasserverbrauch.'en='The total water consumption.'fr='''La consommation totale d'eau.'''sv='Den totala vattenförbrukningen.'}}}", false },
{ "iperl", "driver{name=iperl meter_type=WaterMeter default_fields=name,id,total_m3,max_flow_m3h,timestamp detect{mvt=SEN,68,06 mvt=SEN,68,07 mvt=SEN,7c,07}field{name=total quantity=Volume match{measurement_type=Instantaneous vif_range=Volume}about{de='Der Gesamtwasserverbrauch.'en='The total water consumption.'fr='''La consommation totale d'eau.'''sv='Den totala vattenförbrukningen.'}}field{name=max_flow quantity=Flow match{measurement_type=Instantaneous vif_range=VolumeFlow}about{en='The maximum flow recorded during previous period.'}}}", false },
{ "kampress", "driver{name=kampress default_fields=name,id,status,pressure_bar,max_pressure_bar,min_pressure_bar,timestamp meter_type=PressureSensor detect{mvt=KAM,01,18}field{name=status quantity=Text info=status_and_error_flags match{measurement_type=Instantaneous vif_range=ErrorFlags}lookup{name=ERROR_FLAGS map_type=BitToString mask_bits=0xffff default_message=OK map{name=DROP info='Unexpected drop in pressure in relation to average pressure.'value=0x01 test=Set}map{name=SURGE info='Unexpected increase in pressure in relation to average pressure.'value=0x02 test=Set}map{name=HIGH info='Average pressure has reached configurable limit. Default 15 bar.'value=0x04 test=Set}map{name=LOW info='Average pressure has reached configurable limit. Default 1.5 bar.'value=0x08 test=Set}map{name=TRANSIENT info='Pressure changes quickly over short timeperiods. Average is fluctuating.'value=0x10 test=Set}map{name=COMM_ERROR info='Cannot measure properly or bad internal communication.'value=0x20 test=Set}}}field{name=pressure quantity=Pressure info='The measured pressure.'match{measurement_type=Instantaneous vif_range=Pressure}}field{name=max_pressure quantity=Pressure info='The maximum pressure measured during ?'match{measurement_type=Maximum vif_range=Pressure}}field{name=min_pressure quantity=Pressure info='The minimum pressure measured during ?'match{measurement_type=Minimum vif_range=Pressure}}field{name=alfa info='We do not know what this is.'quantity=Dimensionless vif_scaling=None match{difvifkey=05FF09}}field{name=beta info='We do not know what this is.'quantity=Dimensionless vif_scaling=None match{difvifkey=05FF0A}}}", false },
{ "werhlemodwm", "driver{name=werhlemodwm meter_type=WaterMeter default_fields=name,id,total_m3,timestamp detect{mvt=WZG,03,16}use=meter_datetime use=target_date use=target_m3 use=total_m3 use=fabrication_no field{name=next_target quantity=PointInTime display_unit=date match{measurement_type=Instantaneous vif_range=Date add_combinable=FutureValue storage_nr=1}}}", false },
};
MapToDriver builtins_mvts_[] =
@ -29,4 +31,6 @@ MapToDriver builtins_mvts_[] =
{ { MANUFACTURER_SEN,0x68,0x06 }, "iperl" },
{ { MANUFACTURER_SEN,0x68,0x07 }, "iperl" },
{ { MANUFACTURER_SEN,0x7c,0x07 }, "iperl" },
{ { MANUFACTURER_KAM,0x01,0x18 }, "kampress" },
{ { MANUFACTURER_WZG,0x03,0x16 }, "werhlemodwm" },
};

Wyświetl plik

@ -403,6 +403,14 @@ void log_start_information(Configuration *config)
verbose("(config) using device: %s \n", specified_device.str().c_str());
}
verbose("(config) number of meters: %d\n", config->meters.size());
if (isDebugEnabled())
{
for (MeterInfo &m : config->meters)
{
string aes = AddressExpression::concat(m.address_expressions);
debug("(config) template %s %s %s\n", m.name.c_str(), aes.c_str(), m.str().c_str());
}
}
}
void oneshot_check(Configuration *config, Telegram *t, Meter *meter)
@ -581,12 +589,12 @@ bool start(Configuration *config)
vector<string> envs;
string id = "";
if (meter->ids().size() > 0)
if (meter->addressExpressions().size() > 0)
{
id = meter->idsc().c_str();
id = meter->addressExpressions().back().id;
}
meter->createMeterEnv(&id, &envs, &config->extra_constant_fields);
meter->createMeterEnv(id, &envs, &config->extra_constant_fields);
for (auto &s : *shells) {
vector<string> args;

Wyświetl plik

@ -144,11 +144,12 @@ public:
bool handled = false;
bool exact_id_match = false;
string verbose_info;
string ids;
vector<Address> addresses;
for (auto &m : meters_)
{
bool h = m->handleTelegram(about, input_frame, simulated, &ids, &exact_id_match);
bool h = m->handleTelegram(about, input_frame, simulated, &addresses, &exact_id_match);
if (h) handled = true;
}
@ -156,7 +157,12 @@ public:
// then lets check if there is a template that can create a meter for it.
if (!handled && !exact_id_match)
{
debug("(meter) no meter handled %s checking %d templates.\n", ids.c_str(), meter_templates_.size());
if (isDebugEnabled())
{
string idsc = Address::concat(addresses);
debug("(meter) no meter handled %s checking %d templates.\n",
idsc.c_str(), meter_templates_.size());
}
// Not handled, maybe we have a template to create a new meter instance for this telegram?
Telegram t;
t.about = about;
@ -165,23 +171,34 @@ public:
if (ok)
{
ids = t.idsc;
for (auto &mi : meter_templates_)
{
if (MeterCommonImplementation::isTelegramForMeter(&t, NULL, &mi))
{
// We found a match, make a copy of the meter info.
MeterInfo meter_info = mi;
// Overwrite the wildcard pattern with the highest level id.
// The last id in the t.ids is the highest level id.
// For example: a telegram can have dll_id,tpl_id
// This will pick the tpl_id.
// Or a telegram can have a single dll_id,
// then the dll_id will be picked.
vector<string> tmp_ids;
tmp_ids.push_back(t.ids.back());
meter_info.ids = tmp_ids;
meter_info.idsc = t.ids.back();
// Append the identity to the address expressions.
// The identity is by default the highest level id found.
// I.e. often the tpl_id. This is the last element in t->addresses.
//
// When instantiating a meter from a template we
// make sure the meter triggers exactly on this identity.
// So we append the identity to the address expressions.
//
// E.g. if the template address expression is 12*.M=PII and the meter
// 12345678 is received then the meters address expressions
// will be: 12*.M=PII,12345678
//
// The default type of identity can be changed.
// identitymode=id
// identitymode=id-mfct
// identitymode=full
// identitymode=none
AddressExpression identity_expression;
AddressExpression::appendIdentity(mi.identity_mode,
&identity_expression,
t.addresses,
meter_info.address_expressions);
if (meter_info.driverName().str() == "auto")
{
@ -203,47 +220,59 @@ public:
// Now build a meter object with for this exact id.
auto meter = createMeter(&meter_info);
addMeter(meter);
string idsc = toIdsCommaSeparated(t.ids);
verbose("(meter) used meter template %s %s %s to match %s\n",
mi.name.c_str(),
mi.idsc.c_str(),
mi.driverName().str().c_str(),
idsc.c_str());
if (isVerboseEnabled())
{
string idsc = Address::concat(t.addresses);
string mi_idsc = AddressExpression::concat(mi.address_expressions);
verbose("(meter) used meter template %s %s %s to match %s\n",
mi.name.c_str(),
mi_idsc.c_str(),
mi.driverName().str().c_str(),
idsc.c_str());
}
if (is_daemon_)
{
notice("(wmbusmeters) started meter %d (%s %s %s)\n",
string mi_idsc = AddressExpression::concat(mi.address_expressions);
notice("(wmbusmeters) started meter %d (%s %s %s) identity mode: %s %s\n",
meter->index(),
mi.name.c_str(),
meter_info.idsc.c_str(),
mi.driverName().str().c_str());
mi_idsc.c_str(),
mi.driverName().str().c_str(),
toString(mi.identity_mode),
identity_expression.str().c_str());
}
else
{
verbose("(meter) started meter %d (%s %s %s)\n",
string mi_idsc = AddressExpression::concat(mi.address_expressions);
verbose("(meter) started meter %d (%s %s %s) identity mode: %s %s\n",
meter->index(),
mi.name.c_str(),
meter_info.idsc.c_str(),
mi.driverName().str().c_str());
mi_idsc.c_str(),
mi.driverName().str().c_str(),
toString(mi.identity_mode),
identity_expression.str().c_str());
}
bool match = false;
bool h = meter->handleTelegram(about, input_frame, simulated, &ids, &match);
bool h = meter->handleTelegram(about, input_frame, simulated, &addresses, &match);
if (!match)
{
string aesc = AddressExpression::concat(meter->addressExpressions());
// Oups, we added a new meter object tailored for this telegram
// but it still did not match! This is probably an error in wmbusmeters!
warning("(meter) newly created meter (%s %s %s) did not match telegram! ",
"Please open an issue at https://github.com/wmbusmeters/wmbusmeters/\n",
meter->name().c_str(), meter->idsc().c_str(), meter->driverName().str().c_str());
meter->name().c_str(), aesc.c_str(), meter->driverName().str().c_str());
}
else if (!h)
{
string aesc = AddressExpression::concat(meter->addressExpressions());
// Oups, we added a new meter object tailored for this telegram
// but it still did not handle it! This can happen if the wrong
// decryption key was used.
warning("(meter) newly created meter (%s %s %s) did not handle telegram!\n",
meter->name().c_str(), meter->idsc().c_str(), meter->driverName().str().c_str());
meter->name().c_str(), aesc.c_str(), meter->driverName().str().c_str());
}
else
{
@ -259,7 +288,7 @@ public:
}
if (isVerboseEnabled() && !handled)
{
verbose("(wmbus) telegram from %s ignored by all configured meters!\n", ids.c_str());
verbose("(wmbus) telegram from %s ignored by all configured meters!\n", "TODO");
}
return handled;
}
@ -344,8 +373,8 @@ public:
auto meter = createMeter(&mi);
bool match = false;
string id;
bool h = meter->handleTelegram(about, input_frame, simulated, &id, &match, &t);
vector<Address> addresses;
bool h = meter->handleTelegram(about, input_frame, simulated, &addresses, &match, &t);
if (!match)
{
@ -353,11 +382,12 @@ public:
}
else if (!h)
{
string aesc = AddressExpression::concat(meter->addressExpressions());
// Oups, we added a new meter object tailored for this telegram
// but it still did not handle it! This can happen if the wrong
// decryption key was used. But it is ok if analyzing....
debug("Newly created meter (%s %s %s) did not handle telegram!\n",
meter->name().c_str(), meter->idsc().c_str(), meter->driverName().str().c_str());
meter->name().c_str(), aesc.c_str(), meter->driverName().str().c_str());
}
else
{
@ -406,9 +436,8 @@ public:
// Overwrite the id with the id from the telegram to be analyzed.
MeterInfo mi;
mi.key = analyze_key_;
mi.ids.clear();
mi.ids.push_back(t.ids.back());
mi.idsc = t.ids.back();
mi.address_expressions.clear();
mi.address_expressions.push_back(AddressExpression(t.addresses.back()));
// This will be the driver that will actually decode and print with.
string using_driver;
@ -459,7 +488,6 @@ public:
assert(meter != NULL);
bool match = false;
string id;
if (should_profile_ > 0)
{
@ -473,7 +501,8 @@ public:
for (int k=0; k<should_profile_; ++k)
{
meter->handleTelegram(about, input_frame, simulated, &id, &match, &t);
vector<Address> addresses;
meter->handleTelegram(about, input_frame, simulated, &addresses, &match, &t);
string hr, fields, json;
vector<string> envs, more_json, selected_fields;
@ -500,7 +529,8 @@ public:
return;
}
meter->handleTelegram(about, input_frame, simulated, &id, &match, &t);
vector<Address> addresses;
meter->handleTelegram(about, input_frame, simulated, &addresses, &match, &t);
int u = 0;
int l = 0;

Wyświetl plik

@ -207,6 +207,7 @@ string loadDriver(const string &file, const char *content)
{
DriverInfo di;
debug("(meter) loading %s\n", file.c_str());
bool ok = DriverDynamic::load(&di, file, content);
if (!ok)
{
@ -217,8 +218,15 @@ string loadDriver(const string &file, const char *content)
DriverInfo *old = lookupDriver(di.name().str());
if (old != NULL)
{
debug("(meter) overriding %s\n", di.name().str().c_str());
if (old->getDynamicFileName() != "")
{
if (di.getDynamicFileName() == old->getDynamicFileName())
{
// Loading same file again, happens when using analyze. This is fine.
return di.name().str();
}
// New file source registering the same driver name, nono.
error("Newly loaded driver file %s tries to register the same name %s as driver file %s has already taken!\n",
file.c_str(), di.name().str().c_str(), old->getDynamicFileName().c_str());
}
@ -327,8 +335,8 @@ MeterCommonImplementation::MeterCommonImplementation(MeterInfo &mi,
has_process_content_(di.hasProcessContent()),
waiting_for_poll_response_sem_("waiting_for_poll_response")
{
ids_ = mi.ids;
idsc_ = toIdsCommaSeparated(ids_);
address_expressions_ = mi.address_expressions;
identity_mode_ = mi.identity_mode;
link_modes_ = mi.link_modes;
poll_interval_= mi.poll_interval;
@ -453,6 +461,7 @@ void MeterCommonImplementation::addNumericFieldWithExtractor(string vname,
PrintProperties print_properties,
Quantity vquantity,
VifScaling vif_scaling,
DifSignedness dif_signedness,
FieldMatcher matcher,
Unit display_unit,
double scale)
@ -463,6 +472,7 @@ void MeterCommonImplementation::addNumericFieldWithExtractor(string vname,
vquantity,
display_unit == Unit::Unknown ? defaultUnitForQuantity(vquantity) : display_unit,
vif_scaling,
dif_signedness,
scale,
matcher,
help,
@ -502,6 +512,7 @@ void MeterCommonImplementation::addNumericFieldWithCalculator(string vname,
vquantity,
display_unit == Unit::Unknown ? defaultUnitForQuantity(vquantity) : display_unit,
VifScaling::Auto,
DifSignedness::Signed,
1.0,
FieldMatcher::noMatcher(),
help,
@ -542,6 +553,7 @@ void MeterCommonImplementation::addNumericFieldWithCalculatorAndMatcher(string v
vquantity,
display_unit == Unit::Unknown ? defaultUnitForQuantity(vquantity) : display_unit,
VifScaling::Auto,
DifSignedness::Signed,
1.0,
matcher,
help,
@ -569,6 +581,7 @@ void MeterCommonImplementation::addNumericField(
vquantity,
display_unit == Unit::Unknown ? defaultUnitForQuantity(vquantity) : display_unit,
VifScaling::None,
DifSignedness::Signed,
1.0,
FieldMatcher::noMatcher(),
help,
@ -593,6 +606,7 @@ void MeterCommonImplementation::addStringFieldWithExtractor(string vname,
Quantity::Text,
defaultUnitForQuantity(Quantity::Text),
VifScaling::None,
DifSignedness::Signed,
1.0,
matcher,
help,
@ -618,6 +632,7 @@ void MeterCommonImplementation::addStringFieldWithExtractorAndLookup(string vnam
Quantity::Text,
defaultUnitForQuantity(Quantity::Text),
VifScaling::None,
DifSignedness::Signed,
1.0,
matcher,
help,
@ -641,6 +656,7 @@ void MeterCommonImplementation::addStringField(string vname,
Quantity::Text,
defaultUnitForQuantity(Quantity::Text),
VifScaling::None,
DifSignedness::Signed,
1.0,
FieldMatcher(),
help,
@ -673,25 +689,31 @@ void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
if (!bus_device)
{
warning("(meter) warning! no bus specified for meter %s %s\n", name().c_str(), idsc().c_str());
string aesc = AddressExpression::concat(addressExpressions());
warning("(meter) warning! no bus specified for meter %s %s\n", name().c_str(), aesc.c_str());
return;
}
string id = ids().back();
if (id.length() != 2 && id.length() != 3 && id.length() != 8)
if (addressExpressions().size() == 0)
{
debug("(meter) not polling from bad id \"%s\" with wrong length\n", id.c_str());
warning("(meter) not polling from \"%s\" since no valid id\n", name().c_str());
return;
}
if (id.length() == 2 || id.length() == 3)
AddressExpression &ae = addressExpressions().back();
if (ae.has_wildcard)
{
vector<uchar> idhex;
int idnum = atoi(id.c_str());
warning("(meter) not polling from id \"%s\" since poll id must not have a wildcard\n", ae.id.c_str());
return;
}
if (idnum < 0 || idnum > 250 || idhex.size() != 1)
if (ae.mbus_primary)
{
int idnum = atoi(ae.id.c_str()+1);
if (idnum < 0 || idnum > 250)
{
debug("(meter) not polling from bad id \"%s\"\n", id.c_str());
warning("(meter) not polling from bad id \"%s\"\n", ae.id.c_str());
return;
}
@ -699,7 +721,7 @@ void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
buf.resize(5);
buf[0] = 0x10; // Start
buf[1] = 0x5b; // REQ_UD2
buf[2] = idhex[0];
buf[2] = idnum & 0xff;
uchar cs = 0;
for (int i=1; i<3; ++i) cs += buf[i];
buf[3] = cs; // checksum
@ -707,21 +729,21 @@ void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
verbose("(meter) polling %s %s (primary) with req ud2 on bus %s\n",
name().c_str(),
id.c_str(),
bus_device->busAlias().c_str(),id.c_str());
ae.id.c_str(),
bus_device->busAlias().c_str(),ae.id.c_str());
bus_device->serial()->send(buf);
}
if (id.length() == 8)
if (!ae.mbus_primary)
{
// A full secondary address 12345678 was specified.
vector<uchar> idhex;
bool ok = hex2bin(id, &idhex);
bool ok = hex2bin(ae.id, &idhex);
if (!ok || idhex.size() != 4)
{
debug("(meter) not polling from bad id \"%s\"\n", id.c_str());
warning("(meter) not polling from bad id \"%s\"\n", ae.id.c_str());
return;
}
@ -739,19 +761,19 @@ void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
buf[8] = idhex[2]; // id 56
buf[9] = idhex[1]; // id 34
buf[10] = idhex[0]; // id 12
// Use wildcards instead of exact matching here.
// TODO add selection based on these values as well.
buf[11] = 0xff; // mfct
buf[12] = 0xff; // mfct
buf[13] = 0xff; // version/generation
buf[14] = 0xff; // type/media/device
buf[11] = ae.mfct & 0xff; // mfct
buf[12] = (ae.mfct >> 8) & 0xff; // use 0xff as a wildcard
buf[13] = ae.version; // version/generation
buf[14] = ae.type; // type/media/device
uchar cs = 0;
for (int i=4; i<15; ++i) cs += buf[i];
buf[15] = cs; // checksum
buf[16] = 0x16; // Stop
debug("(meter) secondary addressing bus %s to address %s\n", bus_device->busAlias().c_str(), id.c_str());
debug("(meter) secondary addressing bus %s to address %s\n",
bus_device->busAlias().c_str(),
ae.id.c_str());
bus_device->serial()->send(buf);
usleep(1000*500);
@ -767,26 +789,26 @@ void MeterCommonImplementation::poll(shared_ptr<BusManager> bus_manager)
verbose("(meter) polling %s %s (secondary) with req ud2 bus %s\n",
name().c_str(),
id.c_str(),
ae.id.c_str(),
bus_device->busAlias().c_str());
bus_device->serial()->send(buf);
}
bool ok = waiting_for_poll_response_sem_.wait();
if (!ok)
{
warning("(meter) %s %s did not send a response!\n", name().c_str(), idsc().c_str());
warning("(meter) %s %s did not send a response!\n", name().c_str(), ae.id.c_str());
}
}
}
vector<string>& MeterCommonImplementation::ids()
vector<AddressExpression>& MeterCommonImplementation::addressExpressions()
{
return ids_;
return address_expressions_;
}
string MeterCommonImplementation::idsc()
IdentityMode MeterCommonImplementation::identityMode()
{
return idsc_;
return identity_mode_;
}
vector<FieldInfo> &MeterCommonImplementation::fieldInfos()
@ -852,7 +874,10 @@ void MeterCommonImplementation::setPollInterval(time_t interval)
poll_interval_ = interval;
if (usesPolling() && poll_interval_ == 0)
{
warning("(meter) %s %s needs polling but has no pollinterval set!\n", name().c_str(), idsc().c_str());
string aesc = AddressExpression::concat(addressExpressions());
warning("(meter) %s %s needs polling but has no pollinterval set!\n",
name().c_str(),
aesc.c_str());
}
}
@ -906,8 +931,7 @@ string toString(DriverInfo &di)
bool MeterCommonImplementation::isTelegramForMeter(Telegram *t, Meter *meter, MeterInfo *mi)
{
string name;
vector<string> ids;
string idsc;
vector<AddressExpression> address_expressions;
string driver_name;
assert((meter && !mi) ||
@ -916,26 +940,34 @@ bool MeterCommonImplementation::isTelegramForMeter(Telegram *t, Meter *meter, Me
if (meter)
{
name = meter->name();
ids = meter->ids();
idsc = meter->idsc();
address_expressions = meter->addressExpressions();
driver_name = meter->driverName().str();
}
else
{
name = mi->name;
ids = mi->ids;
idsc = mi->idsc;
address_expressions = mi->address_expressions;
driver_name = mi->driver_name.str();
}
debug("(meter) %s: for me? %s in %s\n", name.c_str(), t->idsc.c_str(), idsc.c_str());
if (isDebugEnabled())
{
// Telegram addresses
string t_idsc = Address::concat(t->addresses);
// Meter/MeterInfo address expressions
string m_idsc = AddressExpression::concat(address_expressions);
debug("(meter) %s: for me? %s in %s\n", name.c_str(), t_idsc.c_str(), m_idsc.c_str());
}
bool used_wildcard = false;
bool id_match = doesIdsMatchExpressions(t->ids, ids, &used_wildcard);
bool match = doesTelegramMatchExpressions(t->addresses,
address_expressions,
&used_wildcard);
if (!id_match) {
if (!match)
{
// The id must match.
debug("(meter) %s: not for me: not my id\n", name.c_str());
debug("(meter) %s: not for me: no match\n", name.c_str());
return false;
}
@ -951,16 +983,11 @@ bool MeterCommonImplementation::isTelegramForMeter(Telegram *t, Meter *meter, Me
// this particular driver, mfct, media, version combo
// is not registered in the METER_DETECTION list in meters.h
/*
if (used_wildcard)
{
// The match for the id was not exact, thus the user is listening using a wildcard
// to many meters and some received matched meter telegrams are not from the right meter type,
// ie their driver does not match. Lets just ignore telegrams that probably cannot be decoded properly.
verbose("(meter) ignoring telegram from %s since it matched a wildcard id rule but driver (%s) does not match.\n",
t->idsc.c_str(), driver_name.c_str());
return false;
}*/
// There was an attempt to give up here if there was a wildcard and it was the wrong driver.
// However some users did expect it to work anyway! This might make sense
// in the future when we have even better dynamic drivers.
// It already make sense if you create an amalgamation driver for several different
// types of meters and want to force the use of this driver.
// The match was exact, ie the user has actually specified 12345678 and foo as driver even
// though they do not match. Lets warn and then proceed. It is common that a user tries a
@ -1040,6 +1067,21 @@ string findField(string key, vector<string> *extra_constant_fields)
return "";
}
string build_id(Address &a, IdentityMode im)
{
string id = a.id;
if (im == IdentityMode::ID_MFCT ||
im == IdentityMode::FULL)
{
id += string(".M=")+manufacturerFlag(a.mfct);
}
if (im == IdentityMode::FULL)
{
id += tostrprintf(".V=%02x.T=%02x", a.version, a.type);
}
return id;
}
// Is the desired field one of the fields common to all meters and telegrams?
bool checkCommonField(string *buf, string desired_field, Meter *m, Telegram *t, char c, bool human_readable)
{
@ -1050,7 +1092,8 @@ bool checkCommonField(string *buf, string desired_field, Meter *m, Telegram *t,
}
if (desired_field == "id")
{
*buf += t->ids.back() + c;
string id = build_id(t->addresses.back(), m->identityMode());
*buf += id + c;
return true;
}
if (desired_field == "timestamp")
@ -1194,7 +1237,8 @@ string concatFields(Meter *m, Telegram *t, char c, vector<FieldInfo> &prints, bo
}
bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<uchar> input_frame,
bool simulated, string *ids, bool *id_match, Telegram *out_analyzed)
bool simulated, vector<Address> *addresses,
bool *id_match, Telegram *out_analyzed)
{
Telegram t;
t.about = about;
@ -1203,7 +1247,7 @@ bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<ucha
if (simulated) t.markAsSimulated();
if (out_analyzed != NULL) t.markAsBeingAnalyzed();
*ids = t.idsc;
*addresses = t.addresses;
if (!ok || !isTelegramForMeter(&t, this, NULL))
{
@ -1212,12 +1256,19 @@ bool MeterCommonImplementation::handleTelegram(AboutTelegram &about, vector<ucha
}
*id_match = true;
verbose("(meter) %s(%d) %s handling telegram from %s\n", name().c_str(), index(), driverName().str().c_str(), t.ids.back().c_str());
if (isVerboseEnabled())
{
verbose("(meter) %s(%d) %s handling telegram from %s\n",
name().c_str(),
index(),
driverName().str().c_str(),
t.addresses.back().str().c_str());
}
if (isDebugEnabled())
{
string msg = bin2hex(input_frame);
debug("(meter) %s %s \"%s\"\n", name().c_str(), t.ids.back().c_str(), msg.c_str());
debug("(meter) %s %s \"%s\"\n", name().c_str(), t.addresses.back().str().c_str(), msg.c_str());
}
// For older meters with manufacturer specific data without a nice 0f dif marker.
@ -1313,7 +1364,6 @@ void MeterCommonImplementation::processFieldExtractors(Telegram *t)
if (fi.hasMatcher() && fi.matches(dve))
{
current_match_nr++;
if (fi.matcher().index_nr != IndexNr(current_match_nr) &&
!fi.matcher().expectedToMatchAgainstMultipleEntries())
{
@ -1628,6 +1678,7 @@ FieldInfo::FieldInfo(int index,
Quantity xuantity,
Unit display_unit,
VifScaling vif_scaling,
DifSignedness dif_signedness,
double scale,
FieldMatcher matcher,
string help,
@ -1644,6 +1695,7 @@ FieldInfo::FieldInfo(int index,
xuantity_(xuantity),
display_unit_(display_unit),
vif_scaling_(vif_scaling),
dif_signedness_(dif_signedness),
scale_(scale),
matcher_(matcher),
help_(help),
@ -1745,11 +1797,11 @@ string FieldInfo::renderJson(Meter *m, DVEntry *dve)
return s;
}
void MeterCommonImplementation::createMeterEnv( string *id,
vector<string> *envs,
vector<string> *extra_constant_fields)
void MeterCommonImplementation::createMeterEnv(string id,
vector<string> *envs,
vector<string> *extra_constant_fields)
{
envs->push_back(string("METER_ID="+*id));
envs->push_back(string("METER_ID="+id));
envs->push_back(string("METER_NAME=")+name());
envs->push_back(string("METER_TYPE=")+driverName().str());
@ -1792,9 +1844,9 @@ void MeterCommonImplementation::printMeter(Telegram *t,
}
string id = "";
if (t->ids.size() > 0)
if (t->addresses.size() > 0)
{
id = t->ids.back();
id = build_id(t->addresses.back(), identityMode());
}
string indent = "";
@ -1854,72 +1906,6 @@ void MeterCommonImplementation::printMeter(Telegram *t,
}
}
}
/*
for (FieldInfo& fi : field_infos_)
{
if (fi.printProperties().hasHIDE()) continue;
// The field should be printed in the json. (Most usually should.)
for (auto& i : t->dv_entries)
{
// Check each telegram dv entry.
DVEntry *dve = &i.second.second;
// Has the entry been matches to this field, then print it as json.
if (dve->hasFieldInfo(&fi))
{
assert(founds[&fi].count(dve) == 0);
founds[&fi].insert(dve);
string field_name = fi.generateFieldNameNoUnit(dve);
found_vnames.insert(field_name);
}
}
}
for (FieldInfo& fi : field_infos_)
{
if (fi.printProperties().hasHIDE()) continue;
if (founds.count(&fi) != 0)
{
// This field info has matched against some dventries.
for (DVEntry *dve : founds[&fi])
{
debug("(meters) render field %s(%s %s)[%d] with dventry @%d key %s data %s\n",
fi.vname().c_str(), toString(fi.xuantity()), unitToStringLowerCase(fi.displayUnit()).c_str(), fi.index(),
dve->offset,
dve->dif_vif_key.str().c_str(),
dve->value.c_str());
string out = fi.renderJson(this, dve);
debug("(meters) %s\n", out.c_str());
s += indent+out+","+newline;
}
}
else
{
// Ok, no value found in received telegram.
// Print field anyway if it is required,
// or if a value has been received before and this field has not been received using a different rule.
// Why this complicated rule?
// E.g. the minmoess mbus seems to use storage 1 for target_m3 but the wmbus version uses storage 8.
// I.e. we have two rules that store into target_m3, this check will prevent target_m3 from being printed twice.
if (fi.printProperties().hasREQUIRED() ||
(hasValue(&fi) && (
found_vnames.count(fi.vname()) == 0 ||
fi.hasFormula()))) // TODO! Fix so a new field total_l does not overwrite total_m3 in mem.
{
// No telegram entries found, but this field should be printed anyway.
// It will be printed with any value received from a previous telegram.
// Or if no value has been received, null.
debug("(meters) render field %s(%s)[%d] without dventry\n",
fi.vname().c_str(), toString(fi.xuantity()), fi.index());
string out = fi.renderJson(this, NULL);
debug("(meters) %s\n", out.c_str());
s += indent+out+","+newline;
}
}
}
*/
s += indent+"\"timestamp\":\""+datetimeOfUpdateRobot()+"\"";
if (t->about.device != "")
@ -1942,7 +1928,7 @@ void MeterCommonImplementation::printMeter(Telegram *t,
s += "}";
*json = s;
createMeterEnv(&id, envs, extra_constant_fields);
createMeterEnv(id, envs, extra_constant_fields);
envs->push_back(string("METER_JSON=")+*json);
envs->push_back(string("METER_MEDIA=")+media);
@ -2094,11 +2080,15 @@ shared_ptr<Meter> createMeter(MeterInfo *mi)
{
newm->setSelectedFields(di->defaultFields());
}
verbose("(meter) created %s %s %s %s\n",
mi->name.c_str(),
di->name().str().c_str(),
mi->idsc.c_str(),
keymsg);
if (isVerboseEnabled())
{
string aesc = AddressExpression::concat(mi->address_expressions);
verbose("(meter) created %s %s %s %s\n",
mi->name.c_str(),
di->name().str().c_str(),
aesc.c_str(),
keymsg);
}
return newm;
}
@ -2166,12 +2156,12 @@ string MeterInfo::str()
return r;
}
bool MeterInfo::parse(string n, string d, string i, string k)
bool MeterInfo::parse(string n, string d, string aes, string k)
{
clear();
name = n;
ids = splitMatchExpressions(i);
address_expressions = splitAddressExpressions(aes);
key = k;
bool driverextras_checked = false;
bool bus_checked = false;
@ -2356,11 +2346,11 @@ bool FieldInfo::extractNumeric(Meter *m, Telegram *t, DVEntry *dve)
}
double extracted_double_value = NAN;
if (dve->extractDouble(&extracted_double_value,
vifScaling() == VifScaling::Auto ||
vifScaling() == VifScaling::AutoSigned,
vifScaling() == VifScaling::NoneSigned ||
vifScaling() == VifScaling::AutoSigned))
bool auto_vif_scaling = vifScaling() == VifScaling::Auto;
bool force_unsigned = difSignedness() == DifSignedness::Unsigned;
if (dve->extractDouble(&extracted_double_value, auto_vif_scaling, force_unsigned))
{
Unit decoded_unit = displayUnit();
if (matcher_.vif_range == VIFRange::DateTime)
@ -2589,85 +2579,6 @@ bool FieldInfo::extractString(Meter *m, Telegram *t, DVEntry *dve)
return found;
}
bool Address::parse(string &s)
{
// Example: 12345678
// or 12345678.M=PII.T=1B.V=01
// or 1234*
// or 1234*.PII
// or 1234*.V01
// or 12 // mbus primary
// or 0 // mbus primary
// or 250.MPII.T1B.V01 // mbus primary
id = "";
mbus_primary = false;
mfct = 0;
type = 0;
version = 0;
if (s.size() == 0) return false;
vector<string> parts = splitString(s, '.');
assert(parts.size() > 0);
if (!isValidMatchExpression(parts[0], true))
{
// Not a long id, so lets check if it is 0-250.
for (size_t i=0; i < parts[0].length(); ++i)
{
if (!isdigit(parts[0][i])) return false;
}
// All digits good.
int v = atoi(parts[0].c_str());
if (v < 0 || v > 250) return false;
// It is 0-250 which means it is an mbus primary address.
mbus_primary = true;
}
id = parts[0];
for (size_t i=1; i<parts[i].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
{
return false;
}
}
return true;
}
bool checkIf(set<string> &fields, const char *s)
{
if (fields.count(s) > 0)
@ -2706,6 +2617,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Time,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::ActualityDuration),
@ -2721,6 +2633,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Time,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::ActualityDuration)
@ -2843,6 +2756,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Time,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::OperatingTime)
@ -2857,6 +2771,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Time,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::OnTime)
@ -2871,6 +2786,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Time,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::AtError)
.set(VIFRange::OnTime)
@ -2933,6 +2849,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Volume)
@ -2947,6 +2864,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Volume)
@ -2962,6 +2880,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::PointInTime,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Date)
@ -2978,6 +2897,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Volume)
@ -2993,6 +2913,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Volume,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::Volume)
@ -3008,6 +2929,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::FlowTemperature)
@ -3022,6 +2944,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::ExternalTemperature)
@ -3036,6 +2959,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Temperature,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::ReturnTemperature)
@ -3049,7 +2973,8 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
"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)
@ -3064,6 +2989,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Flow,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::VolumeFlow)
@ -3078,6 +3004,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::Dimensionless,
VifScaling::None,
DifSignedness::Unsigned,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::AccessNumber)
@ -3092,6 +3019,7 @@ bool MeterCommonImplementation::addOptionalLibraryFields(string field_names)
DEFAULT_PRINT_PROPERTIES,
Quantity::HCA,
VifScaling::Auto,
DifSignedness::Signed,
FieldMatcher::build()
.set(MeasurementType::Instantaneous)
.set(VIFRange::HeatCostAllocation)
@ -3109,10 +3037,8 @@ const char *toString(VifScaling s)
{
switch (s)
{
case VifScaling::None: return "None";
case VifScaling::Auto: return "Auto";
case VifScaling::NoneSigned: return "NoneSigned";
case VifScaling::AutoSigned: return "AutoSigned";
case VifScaling::None: return "None";
case VifScaling::Unknown: return "Unknown";
}
return "?";
@ -3121,14 +3047,32 @@ const char *toString(VifScaling s)
VifScaling toVifScaling(const char *s)
{
if (!s) return VifScaling::Unknown;
if (!strcmp(s, "None")) return VifScaling::None;
if (!strcmp(s, "Auto")) return VifScaling::Auto;
if (!strcmp(s, "NoneSigned")) return VifScaling::NoneSigned;
if (!strcmp(s, "AutoSigned")) return VifScaling::AutoSigned;
if (!strcmp(s, "None")) return VifScaling::None;
if (!strcmp(s, "Unknown")) return VifScaling::Unknown;
return VifScaling::Unknown;
}
const char *toString(DifSignedness s)
{
switch (s)
{
case DifSignedness::Signed: return "Signed";
case DifSignedness::Unsigned: return "Unsigned";
case DifSignedness::Unknown: return "Unknown";
}
return "?";
}
DifSignedness toDifSignedness(const char *s)
{
if (!s) return DifSignedness::Unknown;
if (!strcmp(s, "Signed")) return DifSignedness::Signed;
if (!strcmp(s, "Unsigned")) return DifSignedness::Unsigned;
if (!strcmp(s, "Unknown")) return DifSignedness::Unknown;
return DifSignedness::Unknown;
}
const char* toString(PrintProperty p)
{
switch(p)

Wyświetl plik

@ -18,6 +18,7 @@
#ifndef METER_H_
#define METER_H_
#include"address.h"
#include"dvparser.h"
#include"formula.h"
#include"util.h"
@ -80,22 +81,6 @@ bool isValidKey(const string& key, MeterInfo &mt);
using namespace std;
typedef unsigned char uchar;
struct Address
{
// Example address: 12345678
// Or fully qualified: 12345678.M=PII.T=1b.V=01
// which means manufacturer triplet PII, type/media=0x1b, version=0x01
string id;
bool wildcard_used {}; // The id contains a *
bool mbus_primary {}; // Signals that the id is 0-250
uint16_t mfct {};
uchar type {};
uchar version {};
bool parse(string &s);
};
struct MeterInfo
{
@ -105,8 +90,8 @@ struct MeterInfo
string name; // User specified name of this (group of) meters.
DriverName driver_name; // Will replace MeterDriver.
string extras; // Extra driver specific settings.
vector<string> ids; // Match expressions for ids.
string idsc; // Comma separated ids.
vector<AddressExpression> address_expressions; // Match expressions for ids.
IdentityMode identity_mode {}; // How to group telegram content into objects with state. Default is by id.
string key; // Decryption key.
LinkModeSet link_modes;
int bps {}; // For mbus communication you need to know the baud rate.
@ -126,13 +111,12 @@ struct MeterInfo
string str();
DriverName driverName();
MeterInfo(string b, string n, string e, vector<string> i, string k, LinkModeSet lms, int baud, vector<string> &s, vector<string> &ms, vector<string> &j, vector<string> &calcfs)
MeterInfo(string b, string n, string e, vector<AddressExpression> aes, string k, LinkModeSet lms, int baud, vector<string> &s, vector<string> &ms, vector<string> &j, vector<string> &calcfs)
{
bus = b;
name = n;
extras = e,
ids = i;
idsc = toIdsCommaSeparated(ids);
address_expressions = aes;
key = k;
shells = s;
meter_shells = ms;
@ -146,8 +130,7 @@ struct MeterInfo
{
bus = "";
name = "";
ids.clear();
idsc = "";
address_expressions.clear();
key = "";
shells.clear();
meter_shells.clear();
@ -246,16 +229,24 @@ vector<DriverInfo*>& allDrivers();
enum class VifScaling
{
None, // No auto scaling.
Auto, // Scale to normalized VIF unit (ie kwh, m3, m3h etc)
NoneSigned, // No auto scaling however assume the value is signed.
AutoSigned, // Scale and assume the value is signed.
None, // No auto scaling.
Unknown
};
const char* toString(VifScaling s);
VifScaling toVifScaling(const char *s);
enum class DifSignedness
{
Signed, // By default the binary values are interpreted as signed.
Unsigned, // We can override for non-compliant meters.
Unknown
};
const char* toString(DifSignedness s);
DifSignedness toDifSignedness(const char *s);
enum PrintProperty
{
REQUIRED = 1, // If no data has arrived, then print this field anyway with NaN or null.
@ -300,6 +291,7 @@ struct FieldInfo
Quantity quantity,
Unit display_unit,
VifScaling vif_scaling,
DifSignedness dif_signedness,
double scale,
FieldMatcher matcher,
string help,
@ -317,6 +309,7 @@ struct FieldInfo
Quantity xuantity() { return xuantity_; }
Unit displayUnit() { return display_unit_; }
VifScaling vifScaling() { return vif_scaling_; }
DifSignedness difSignedness() { return dif_signedness_; }
double scale() { return scale_; }
FieldMatcher& matcher() { return matcher_; }
string help() { return help_; }
@ -354,6 +347,7 @@ private:
Quantity xuantity_; // Quantity: Energy, Volume
Unit display_unit_; // Selected display unit for above quantity: KWH, M3
VifScaling vif_scaling_;
DifSignedness dif_signedness_;
double scale_; // A hardcoded scale factor. Used only for manufacturer specific values with unknown units for the vifs.
FieldMatcher matcher_;
string help_; // Helpful information on this meters use of this value.
@ -389,10 +383,9 @@ struct Meter
virtual void setIndex(int i) = 0;
// Use this bus to send messages to the meter.
virtual string bus() = 0;
// This meter listens to these ids.
virtual vector<string> &ids() = 0;
// Comma separated ids.
virtual string idsc() = 0;
// This meter listens to these address expressions.
virtual std::vector<AddressExpression>& addressExpressions() = 0;
virtual IdentityMode identityMode() = 0;
// This meter can report these fields, like total_m3, temp_c.
virtual vector<FieldInfo> &fieldInfos() = 0;
virtual vector<string> &extraConstantFields() = 0;
@ -422,7 +415,7 @@ struct Meter
virtual void onUpdate(std::function<void(Telegram*t,Meter*)> cb) = 0;
virtual int numUpdates() = 0;
virtual void createMeterEnv(string *id,
virtual void createMeterEnv(string id,
vector<string> *envs,
vector<string> *more_json) = 0;
virtual void printMeter(Telegram *t,
@ -438,7 +431,8 @@ struct Meter
// Returns true of this meter handled this telegram!
// Sets id_match to true, if there was an id match, even though the telegram could not be properly handled.
virtual bool handleTelegram(AboutTelegram &about, vector<uchar> input_frame,
bool simulated, string *id, bool *id_match, Telegram *out_t = NULL) = 0;
bool simulated, std::vector<Address> *addresses,
bool *id_match, Telegram *out_t = NULL) = 0;
virtual MeterKeys *meterKeys() = 0;
virtual void addExtraCalculatedField(std::string ecf) = 0;

Wyświetl plik

@ -59,8 +59,8 @@ struct MeterCommonImplementation : public virtual Meter
int index();
void setIndex(int i);
string bus();
vector<string>& ids();
string idsc();
vector<AddressExpression>& addressExpressions();
IdentityMode identityMode();
vector<FieldInfo> &fieldInfos();
vector<string> &extraConstantFields();
string name();
@ -85,7 +85,6 @@ struct MeterCommonImplementation : public virtual Meter
static bool isTelegramForMeter(Telegram *t, Meter *meter, MeterInfo *mi);
MeterKeys *meterKeys();
// MeterCommonImplementation(MeterInfo &mi, string driver);
MeterCommonImplementation(MeterInfo &mi, DriverInfo &di);
~MeterCommonImplementation() = default;
@ -112,6 +111,7 @@ protected:
PrintProperties print_properties, // Should this be printed by default in fields,json and hr.
Quantity vquantity, // Value belongs to this quantity, this quantity determines the default unit.
VifScaling vif_scaling, // How should any Vif value be scaled.
DifSignedness dif_signedness, // Should we override the default signed assumption for binary values?
FieldMatcher matcher,
Unit display_unit = Unit::Unknown, // If specified use this unit for the json field instead instead of the default unit.
double scale = 1.0); // A hard coded extra scale factor. Useful for manufacturer specific values.
@ -163,8 +163,9 @@ protected:
// Override for mbus meters that need to be queried and likewise for C2/T2 wmbus-meters.
void poll(shared_ptr<BusManager> bus);
bool handleTelegram(AboutTelegram &about, vector<uchar> frame,
bool simulated, string *id, bool *id_match, Telegram *out_analyzed = NULL);
void createMeterEnv(string *id,
bool simulated, std::vector<Address> *addresses,
bool *id_match, Telegram *out_analyzed = NULL);
void createMeterEnv(string id,
vector<string> *envs,
vector<string> *more_json); // Add this json "key"="value" strings.
void printMeter(Telegram *t,
@ -221,8 +222,8 @@ private:
ELLSecurityMode expected_ell_sec_mode_ {};
TPLSecurityMode expected_tpl_sec_mode_ {};
string name_;
vector<string> ids_;
string idsc_;
vector<AddressExpression> address_expressions_;
IdentityMode identity_mode_;
vector<function<void(Telegram*,Meter*)>> on_update_;
int num_updates_ {};
time_t datetime_of_update_ {};

Wyświetl plik

@ -92,10 +92,10 @@ void Printer::printFiles(Meter *meter, Telegram *t, string &human_readable, stri
snprintf(filename, 127, "%s/%s", meterfiles_dir_.c_str(), meter->name().c_str());
break;
case MeterFileNaming::Id:
snprintf(filename, 127, "%s/%s", meterfiles_dir_.c_str(), t->ids.back().c_str());
snprintf(filename, 127, "%s/%s", meterfiles_dir_.c_str(), t->addresses.back().id.c_str());
break;
case MeterFileNaming::NameId:
snprintf(filename, 127, "%s/%s-%s", meterfiles_dir_.c_str(), meter->name().c_str(), t->ids.back().c_str());
snprintf(filename, 127, "%s/%s-%s", meterfiles_dir_.c_str(), meter->name().c_str(), t->addresses.back().id.c_str());
break;
}
string stamp;

Wyświetl plik

@ -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)
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
@ -15,6 +15,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include"address.h"
#include"aes.h"
#include"aescmac.h"
#include"cmdline.h"
@ -37,12 +38,13 @@ using namespace std;
bool verbose_ = false;
#define LIST_OF_TESTS \
X(addresses) \
X(dynamic_loading) \
X(crc) \
X(dvparser) \
X(devices) \
X(linkmodes) \
X(ids) \
X(addresses) \
X(kdf) \
X(periods) \
X(device_parsing) \
@ -422,7 +424,7 @@ void test_linkmodes()
void test_valid_match_expression(string s, bool expected)
{
bool b = isValidMatchExpressions(s, false);
bool b = isValidSequenceOfAddressExpressions(s);
if (b == expected) return;
if (expected == true)
{
@ -436,9 +438,13 @@ void test_valid_match_expression(string s, bool expected)
void test_does_id_match_expression(string id, string mes, bool expected, bool expected_uw)
{
vector<string> expressions = splitMatchExpressions(mes);
Address a;
a.id = id;
vector<Address> as;
as.push_back(a);
vector<AddressExpression> expressions = splitAddressExpressions(mes);
bool uw = false;
bool b = doesIdMatchExpressions(id, expressions, &uw);
bool b = doesTelegramMatchExpressions(as, expressions, &uw);
if (b != expected)
{
if (expected == true)
@ -494,9 +500,15 @@ void test_ids()
test_does_id_match_expression("78563413", "*,!00156327,!00048713", true, true);
}
void tst_address(string s, bool valid, string id, string mfct, uchar type, uchar version)
void tst_address(string s, bool valid,
string id, bool has_wildcard,
string mfct,
uchar version,
uchar type,
bool mbus_primary,
bool filter_out)
{
Address a;
AddressExpression a;
bool ok = a.parse(s);
if (ok != valid)
@ -509,39 +521,182 @@ void tst_address(string s, bool valid, string id, string mfct, uchar type, uchar
{
string smfct = manufacturerFlag(a.mfct);
if (id != a.id ||
has_wildcard != a.has_wildcard ||
mfct != smfct ||
version != a.version ||
type != a.type ||
version != a.version)
mbus_primary != a.mbus_primary ||
filter_out != a.filter_out)
{
printf("Expected parse of address \"%s\" to return (id=%s mfct=%s type=%02x version=%02x) "
"but got (id=%s mfct=%s type=%02x version=%02x)\n",
printf("Expected parse of address \"%s\" to return\n"
"(id=%s haswild=%d mfct=%s version=%02x type=%02x mbus=%d negt=%d)\n"
"but got\n"
"(id=%s haswild=%d mfct=%s version=%02x type=%02x mbus=%d negt=%d)\n",
s.c_str(),
id.c_str(), mfct.c_str(), type, version,
a.id.c_str(), smfct.c_str(), a.type, a.version);
id.c_str(),
has_wildcard,
mfct.c_str(),
version,
type,
mbus_primary,
filter_out,
a.id.c_str(),
a.has_wildcard,
smfct.c_str(),
a.version,
a.type,
a.mbus_primary,
a.filter_out);
}
}
}
void tst_address_match(string expr, string id, uint16_t m, uchar v, uchar t, bool match, bool filter_out)
{
AddressExpression e;
bool ok = e.parse(expr);
assert(ok);
bool test = e.match(id, m, v, t);
if (test != match)
{
printf("Expected address %s %04x %02x %02x to %smatch expression %s\n",
id.c_str(),
m, v, t,
match?"":"not ",
expr.c_str());
}
if (match && e.filter_out != filter_out)
{
printf("Expected %s from match expression %s\n",
filter_out?"FILTERED OUT":"NOT filtered",
expr.c_str());
}
}
void tst_telegram_match(string addresses, string expressions, bool match, bool uw)
{
vector<AddressExpression> exprs = splitAddressExpressions(expressions);
vector<AddressExpression> as = splitAddressExpressions(addresses);
vector<Address> addrs;
for (auto &ad : as)
{
Address a;
a.id = ad.id;
a.mfct = ad.mfct;
a.version = ad.version;
a.type = ad.type;
addrs.push_back(a);
}
bool used_wildcard = false;
bool m = doesTelegramMatchExpressions(addrs, exprs, &used_wildcard);
if (m != match)
{
printf("Expected addresses %s to %smatch expressions %s\n",
addresses.c_str(),
match?"":"NOT ",
expressions.c_str());
}
if (uw != used_wildcard)
{
printf("Expected addresses %s from match expression %s %susing wildcard\n",
addresses.c_str(),
expressions.c_str(),
uw?"":"NOT ");
}
}
void test_addresses()
{
/*
tst_address("12345678",
true,
"12345678", // id
"@@@", // mfct
0, // type
0 // version
true,
"12345678", // id
false, // has wildcard
"___", // mfct
0xff, // type
0xff, // version
false, // mbus primary found
false // negate test
);
tst_address("123k45678", false, "", false, "", 0xff, 0xff, false, false);
tst_address("1234", false, "", false, "", 0xff, 0xff, false, false);
tst_address("p0", true, "p0", false, "___", 0xff, 0xff, true, false);
tst_address("p250", true, "p250", false, "___", 0xff, 0xff, true, false);
tst_address("p251", false, "", false, "", 0xff, 0xff, false, false);
tst_address("p0.M=PII.V=01.T=1b", true, "p0", false, "PII", 0x01, 0x1b, true, false);
tst_address("p123.V=11.M=FOO.T=ff", true, "p123", false, "FOO", 0x11, 0xff, true, false);
tst_address("p123.M=FOO", true, "p123", false, "FOO", 0xff, 0xff, true, false);
tst_address("p123.M=FOO.V=33", true, "p123", false, "FOO", 0x33, 0xff, true, false);
tst_address("p123.T=33", true, "p123", false, "___", 0xff, 0x33, true, false);
tst_address("p1.V=33", true, "p1", false, "___", 0x33, 0xff, true, false);
tst_address("p16.M=BAR", true, "p16", false, "BAR", 0xff, 0xff, true, false);
tst_address("123k45678", false, "", "", 0, 0);
tst_address("1234", false, "", "", 0, 0);
tst_address("0", true, "0", "@@@", 0, 0);
tst_address("250", true, "250", "@@@", 0, 0);
tst_address("251", false, "", "", 0, 0);
tst_address("0.M=PII.T=1b.V=01", true, "0", "PII", 0x1b, 0x01);
tst_address("123.V=11.M=FOO.T=ff", true, "123", "FOO", 0xff, 0x11);
tst_address("16.M=BAR", true, "16", "BAR", 0, 0);
*/
tst_address("12345678.M=ABB.V=66.T=16", true, "12345678", false, "ABB", 0x66, 0x16, false, false);
tst_address("!12345678.M=ABB.V=66.T=16", true, "12345678", false, "ABB", 0x66, 0x16, false, true);
tst_address("!*.M=ABB", true, "*", true, "ABB", 0xff, 0xff, false, true);
tst_address("!*.V=66.T=06", true, "*", true, "___", 0x66, 0x06, false, true);
tst_address("12*", true, "12*", true, "___", 0xff, 0xff, false, false);
tst_address("!1234567*", true, "1234567*", true, "___", 0xff, 0xff, false, true);
tst_address_match("12345678", "12345678", 1, 1, 1, true, false);
tst_address_match("12345678.M=ABB.V=77", "12345678", MANUFACTURER_ABB, 0x77, 88, true, false);
tst_address_match("1*.V=77", "12345678", MANUFACTURER_ABB, 0x77, 1, true, false);
tst_address_match("12345678.M=ABB.V=67.T=06", "12345678", MANUFACTURER_ABB, 0x67, 0x06, true, false);
tst_address_match("12345678.M=ABB.V=67.T=06", "12345678", MANUFACTURER_ABB, 0x68, 0x06, false, false);
tst_address_match("12345678.M=ABB.V=67.T=06", "12345678", MANUFACTURER_ABB, 0x67, 0x07, false, false);
tst_address_match("12345678.M=ABB.V=67.T=06", "12345678", MANUFACTURER_ABB+1, 0x67, 0x06, false, false);
tst_address_match("12345678.M=ABB.V=67.T=06", "12345677", MANUFACTURER_ABB, 0x67, 0x06, false, false);
// Now verify filter out ! character. The filter out does notchange the test. It is still the same
// test, but the match will be used as a filter out. Ie if the match triggers, then the telegram will be filtered out.
tst_address_match("!12345678", "12345677", 1, 1, 1, false, false);
tst_address_match("!*.M=ABB", "99999999", MANUFACTURER_ABB, 1, 1, true, true);
tst_address_match("*.M=ABB", "99999999", MANUFACTURER_ABB, 1, 1, true, false);
// Test that both id wildcard matches and the version.
tst_address_match("9*.V=06", "99999999", MANUFACTURER_ABB, 0x06, 1, true, false);
tst_address_match("9*.V=06", "89999999", MANUFACTURER_ABB, 0x06, 1, false, false);
tst_address_match("9*.V=06", "99999999", MANUFACTURER_ABB, 0x07, 1, false, false);
tst_address_match("9*.V=06", "89999999", MANUFACTURER_ABB, 0x07, 1, false, false);
// Test the same, expect same answers but check that filtered out is set.
tst_address_match("!9*.V=06", "99999999", MANUFACTURER_ABB, 0x06, 1, true, true);
tst_address_match("!9*.V=06", "89999999", MANUFACTURER_ABB, 0x06, 1, false, true);
tst_address_match("!9*.V=06", "99999999", MANUFACTURER_ABB, 0x07, 1, false, true);
tst_address_match("!9*.V=06", "89999999", MANUFACTURER_ABB, 0x07, 1, false, true);
tst_telegram_match("12345678", "12345678", true, false);
tst_telegram_match("11111111,22222222", "12345678,22*", true, true);
tst_telegram_match("11111111,22222222", "12345678,22222222", true, false);
tst_telegram_match("11111111.M=KAM,22222222.M=PII", "11111111.M=KAM", true, false);
tst_telegram_match("11111111.M=KAF", "11111111.M=KAM", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAM", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAF", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAM", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.V=1b", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.T=16", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAM.T=16", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAM.V=1b", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.T=16.V=1b", true, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAL", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.V=1c", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.T=17", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAM.T=17", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.M=KAL.V=1b", false, false);
tst_telegram_match("11111111.M=KAM.V=1b.T=16", "11111111.T=17.V=1b", false, false);
// Test * matches both 11111111 and 2222222 but the only the 111111 matches the filter out V=1b.
// Verify that the filter out !1*.V=1b will override successfull match (with no filter out) * for 22222222.
tst_telegram_match("11111111.M=KAM.V=1b.T=16,22222222.M=XXX.V=aa.T=99", "*,!1*.V=1b", false, true);
}
void eq(string a, string b, const char *tn)
@ -1228,13 +1383,13 @@ void test_translate()
{
Translate::Lookup lookup1 =
Translate::Lookup()
.add(Translate::Rule("ACCESS_BITS", Translate::Type::BitToString)
.add(Translate::Rule("ACCESS_BITS", Translate::MapType::BitToString)
.set(MaskBits(0xf0))
.add(Translate::Map(0x10, "NO_ACCESS", TestBit::Set))
.add(Translate::Map(0x20, "ALL_ACCESS", TestBit::Set))
.add(Translate::Map(0x40, "TEMP_ACCESS", TestBit::Set))
)
.add(Translate::Rule("ACCESSOR_TYPE", Translate::Type::IndexToString)
.add(Translate::Rule("ACCESSOR_TYPE", Translate::MapType::IndexToString)
.set(MaskBits(0x0f))
.add(Translate::Map(0x00, "ACCESSOR_RED", TestBit::Set))
.add(Translate::Map(0x07, "ACCESSOR_GREEN", TestBit::Set))
@ -1246,7 +1401,7 @@ void test_translate()
{
{
"FLOW_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger,
MaskBits(0x3f),
"OOOK",
@ -1265,7 +1420,7 @@ void test_translate()
{
{
"NO_FLAGS",
Translate::Type::BitToString,
Translate::MapType::BitToString,
AlwaysTrigger,
MaskBits(0x03),
"OK",
@ -2028,6 +2183,8 @@ LIST_OF_QUANTITIES
test_si_convert(2211717, 2211717, Unit::FACTOR, "counter", Unit::COUNTER, "counter", Quantity::Dimensionless, &from_set, &to_set);
test_si_convert(2211717, 2211717, Unit::NUMBER, "counter", Unit::COUNTER, "counter", Quantity::Dimensionless, &from_set, &to_set);
test_si_convert(2211717, 2211717, Unit::FACTOR, "counter", Unit::NUMBER, "counter", Quantity::Dimensionless, &from_set, &to_set);
test_si_convert(2211717, 2211717, Unit::PERCENTAGE, "counter", Unit::NUMBER, "counter", Quantity::Dimensionless, &from_set, &to_set);
test_si_convert(2211717, 2211717, Unit::NUMBER, "counter", Unit::PERCENTAGE, "counter", Quantity::Dimensionless, &from_set, &to_set);
check_units_tested(from_set, to_set, Quantity::Dimensionless);
@ -2161,9 +2318,9 @@ void test_formulas_building_meters()
MeterKeys mk;
t.parse(frame, &mk, true);
string id;
vector<Address> addresses;
bool match;
meter->handleTelegram(t.about, frame, true, &id, &match, &t);
meter->handleTelegram(t.about, frame, true, &addresses, &match, &t);
f->clear();
f->setMeter(meter.get());
@ -2212,7 +2369,7 @@ void test_formulas_building_meters()
MeterKeys mk;
t.parse(frame, &mk, true);
string id;
vector<Address> id;
bool match;
meter->handleTelegram(t.about, frame, true, &id, &match, &t);
@ -2396,7 +2553,7 @@ void test_formulas_parsing_1()
MeterKeys mk;
t.parse(frame, &mk, true);
string id;
vector<Address> id;
bool match;
meter->handleTelegram(t.about, frame, true, &id, &match, &t);
@ -2446,7 +2603,7 @@ void test_formulas_parsing_2()
MeterKeys mk;
t.parse(frame, &mk, true);
string id;
vector<Address> id;
bool match;
meter->handleTelegram(t.about, frame, true, &id, &match, &t);
@ -2588,3 +2745,22 @@ void test_formulas_stringinterpolation()
}
}
void test_dynamic_loading()
{
VIFRange vr = toVIFRange("Date");
if (vr != VIFRange::Date)
{
printf("ERROR in dynamic loading got %s but expected %s!\n",
toString(vr), toString(VIFRange::Date));
}
vr = toVIFRange("DateTime");
if (vr != VIFRange::DateTime)
{
printf("ERROR in dynamic loading got %s but expected %s!\n",
toString(vr), toString(VIFRange::DateTime));
}
}

Wyświetl plik

@ -19,6 +19,7 @@
#include"util.h"
#include<assert.h>
#include<string.h>
using namespace Translate;
using namespace std;
@ -210,15 +211,15 @@ void handleRule(Rule& rule, string &s, uint64_t bits)
{
switch (rule.type)
{
case Type::BitToString:
case MapType::BitToString:
handleBitToString(rule, s, bits);
break;
case Type::IndexToString:
case MapType::IndexToString:
handleIndexToString(rule, s, bits);
break;
case Type::DecimalsToString:
case MapType::DecimalsToString:
handleDecimalsToString(rule, s, bits);
break;
@ -259,11 +260,19 @@ string Lookup::str()
return x;
}
Translate::MapType toMapType(const char *s)
{
if (!strcmp(s, "BitToString")) return Translate::MapType::BitToString;
if (!strcmp(s, "IndexToString")) return Translate::MapType::IndexToString;
if (!strcmp(s, "DecimalsToString")) return Translate::MapType::DecimalsToString;
return Translate::MapType::Unknown;
}
Lookup NoLookup = {};
Map m = { 123, "howdy" };
vector<Map> vm = { { 123, "howdy" } };
Rule r = { "name", Translate::Type::IndexToString,
Rule r = { "name", Translate::MapType::IndexToString,
AlwaysTrigger, MaskBits(0xe000), "", { } };

Wyświetl plik

@ -66,8 +66,9 @@ private:
namespace Translate
{
enum class Type
enum class MapType
{
Unknown,
BitToString, // A bit translates to a text string.
IndexToString, // A masked set of bits (a number) translates to a lookup index with text strings.
DecimalsToString // Numbers are successively subtracted from input, each successfull subtraction translate into a text string.
@ -86,16 +87,16 @@ namespace Translate
struct Rule
{
std::string name;
Type type;
MapType type;
TriggerBits trigger; // Bits that must be set.
MaskBits mask; // Bits to be used are set as 1.
DefaultMessage default_message; // If no bits are set print this, typically "OK" or "".
std::vector<Map> map;
Rule() {};
Rule(std::string n, Type t, TriggerBits tr, MaskBits mb, std::string dm, std::vector<Map> m)
Rule(std::string n, MapType t, TriggerBits tr, MaskBits mb, std::string dm, std::vector<Map> m)
: name(n), type(t), trigger(tr), mask(mb), default_message(dm), map(m) {}
Rule(std::string n, Type t) :
Rule(std::string n, MapType t) :
name(n), type(t), trigger(AlwaysTrigger), mask(AutoMask), default_message(DefaultMessage("")) {}
Rule &set(TriggerBits t) { trigger = t; return *this; }
Rule &set(MaskBits m) { mask = m; return *this; }
@ -116,6 +117,8 @@ namespace Translate
};
};
Translate::MapType toMapType(const char *s);
extern Translate::Lookup NoLookup;
#endif

Some files were not shown because too many files have changed in this diff Show More