kopia lustrzana https://github.com/weetmuts/wmbusmeters
Porównaj commity
29 Commity
Autor | SHA1 | Data |
---|---|---|
Fredrik Öhrström | 1a4169ed23 | |
PovilasID | aa4f1956e8 | |
Fredrik Öhrström | d90dbb196e | |
Fredrik Öhrström | 14d021426a | |
Michał Morański | f32179a939 | |
Fredrik Öhrström | a32fcfdf9a | |
Fredrik Öhrström | efcc41d107 | |
Fredrik Öhrström | a69e547a17 | |
Fredrik Öhrström | 23f2279a64 | |
Fredrik Öhrström | 05edab0882 | |
Fredrik Öhrström | ff72e1debc | |
Fredrik Öhrström | c1509f6139 | |
Fredrik Öhrström | 9facddf019 | |
Fredrik Öhrström | 9a34a55abb | |
Fredrik Öhrström | 465a450a8b | |
Jean-Samuel REYNAUD | 9576550f85 | |
Fredrik Öhrström | 1f2cd10160 | |
Fredrik Öhrström | 8c09f7b2d8 | |
Fredrik Öhrström | 3247a4a576 | |
Fredrik Öhrström | 23779cb9f7 | |
Fredrik Öhrström | 5962e727ff | |
Arthur van Dorp | 03d95e780e | |
Fredrik Öhrström | 11c83c1f37 | |
Fredrik Öhrström | 7634b95438 | |
Fredrik Öhrström | 78e7c47503 | |
Fredrik Öhrström | 0c98b474bb | |
Fredrik Öhrström | 9d27ab3fb3 | |
Fredrik Öhrström | c21efd1d69 | |
testuser7 | 67230b4213 |
|
@ -11,8 +11,8 @@ on:
|
|||
env:
|
||||
DOCKERHUB_IMAGE: ${{ github.repository }}
|
||||
IMAGE_TAG: |
|
||||
${{ github.ref_type == 'tag' && (contains(github.ref_name, '-RC') &&
|
||||
format('{0}-{1}', 'candidate', github.ref_name) || format('{0}-{1}', '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:
|
||||
|
|
29
CHANGES
29
CHANGES
|
@ -1,3 +1,32 @@
|
|||
|
||||
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.
|
||||
|
|
4
Makefile
4
Makefile
|
@ -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 \
|
||||
|
|
52
README.md
52
README.md
|
@ -6,6 +6,33 @@ wireless wm-bus meters. The readings can then be published using
|
|||
MQTT, curled to a REST api, inserted into a database or stored in a
|
||||
log file.
|
||||
|
||||
# What does it do?
|
||||
|
||||
Wmbusmeters converts incoming telegrams from (w)mbus/OMS compatible meters like:
|
||||
`1844AE4C4455223368077A55000000_041389E20100023B0000`
|
||||
|
||||
into human readable:
|
||||
`MyTapWater 33225544 123.529 m³ 0 m³/h 2024-03-03 19:36:22`
|
||||
|
||||
or into csv:
|
||||
`MyTapWater;33225544;123.529;0;2024-03-03 19:36:45`
|
||||
|
||||
or into json:
|
||||
```json
|
||||
{
|
||||
"media":"water",
|
||||
"meter":"iperl",
|
||||
"name":"MyTapWater",
|
||||
"id":"33225544",
|
||||
"max_flow_m3h":0,
|
||||
"total_m3":123.529,
|
||||
"timestamp":"2024-03-03T18:37:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
Wmbusmeters can collect telegrams from radio using hardware dongles or rtl-sdr software radio dongles,
|
||||
or from m-bus meters using serial ports, or from files/pipes.
|
||||
|
||||
[FAQ/WIKI/MANUAL pages](https://wmbusmeters.github.io/wmbusmeters-wiki/)
|
||||
|
||||
The program runs on GNU/Linux, MacOSX, FreeBSD, and Raspberry Pi.
|
||||
|
@ -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
|
||||
|
@ -419,6 +454,7 @@ As {options} you can use:
|
|||
--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,
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
telegram=|7B4479169977997730378C208B900F002C25E4EF0A002EA98E7D58B3ADC57299779977991611028B005087102F2F#0DFD090F34302e3030562030303030303030300D790E31323334353637383839595345310DFD100AAAAAAAAAAAAAAAAAAAAA0D780E31323334353637383930594553312F2F2F2F2F2F2F2F2F2F2F|
|
||||
telegram=|7B4479169977997730378C20F0900F002C2549EE0A0077C19D3D1A08ABCD729977997779161102F0005007102F2F#0702F5C3FA000000000007823C5407000000000000841004E081020084200415000000042938AB000004A9FF01FA0A000004A9FF02050A000004A9FF03389600002F2F2F2F2F2F2F2F2F2F2F2F2F|
|
|
@ -0,0 +1,19 @@
|
|||
telegram=|A244EE4D785634123C067A8F000000_0C1348550000426CE1F14C130000000082046C21298C0413330000008D04931E3A3CFE3300000033000000330000003300000033000000330000003300000033000000330000003300000033000000330000004300000034180000046D0D0B5C2B03FD6C5E150082206C5C290BFD0F0200018C4079678885238310FD3100000082106C01018110FD610002FD66020002FD170000|
|
||||
{"media":"warm water","meter":"supercom587","name":"MyWarmWater","id":"12345678","total_m3":5.548,"software_version":"010002","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
|MyWarmWater;12345678;5.548;1111-11-11 11:11.11
|
||||
|
||||
telegram=|A244EE4D111111113C077AAC000000_0C1389490000426CE1F14C130000000082046C21298C0413010000008D04931E3A3CFE0100000001000000010000000100000001000000010000000100000001000000010000000100000001000000010000001600000031130000046D0A0C5C2B03FD6C60150082206C5C290BFD0F0200018C4079629885238310FD3100000082106C01018110FD610002FD66020002FD170000|
|
||||
{"media":"water","meter":"supercom587","name":"MyColdWater","id":"11111111","total_m3":4.989,"software_version":"010002","status":"OK","timestamp":"1111-11-11T11:11:11Z"}
|
||||
|MyColdWater;11111111;4.989;1111-11-11 11:11.11
|
||||
|
||||
telegram=|1E44AE4C9956341268077A36001000_2F2F0413181E0000023B00002F2F2F2F|
|
||||
{"media":"water","meter":"iperl","name":"MoreWater","id":"12345699","total_m3":7.704,"max_flow_m3h":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|MoreWater;12345699;7.704;0;1111-11-11 11:11.11
|
||||
|
||||
telegram=|1844AE4C4455223368077A55000000_041389E20100023B0000|
|
||||
{"media":"water","meter":"iperl","name":"WaterWater","id":"33225544","total_m3":123.529,"max_flow_m3h":0,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|WaterWater;33225544;123.529;0;1111-11-11 11:11.11
|
||||
|
||||
telegram=|31446850226677116980A0119F27020480048300C408F709143C003D341A2B0B2A0707000000000000062D114457563D71A1850000|
|
||||
{"media":"heat cost allocator","meter":"fhkvdataiii","name":"Room","id":"11776622","current_hca":131,"current_date":"2020-02-08T02:00:00Z","previous_hca":1026,"previous_date":"2019-12-31T02:00:00Z","temp_room_c":22.44,"temp_radiator_c":25.51,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
|Room;11776622;131;2020-02-08T02:00:00Z;1026;2019-12-31T02:00:00Z;22.44;25.51;1111-11-11 11:11.11
|
|
@ -0,0 +1,4 @@
|
|||
telegram=|414493447514916746377275149167934446044D000020_0C06490000004C0600000000426CFF2CCC080611000000C2086C1F3102FD170000326CFFFF046D330F1432|
|
||||
telegram=|5b44934475149167463778077975149167934446040dff5f3500823d0000810007c006ffff49000000ff2c000000001f3111000000008000800080008000800080008000800080000000000B002f02fd170000046d390d1432488408|
|
||||
telegram=|414493447514916746377275149167934446044D000020_0C06490000004C0600000000426CFF2CCC080611000000C2086C1F3102FD170000326CFFFF046D330F1432|
|
||||
telegram=|5b44934475149167463778077975149167934446040dff5f3500823d0000810007c006ffff49000000ff2c000000001f3111000000008000800080008000800080008000800080000000000B002f02fd170000046d390d1432488408|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,656 @@
|
|||
/*
|
||||
Copyright (C) 2017-2024 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include"address.h"
|
||||
#include"manufacturers.h"
|
||||
|
||||
#include<assert.h>
|
||||
#include<algorithm>
|
||||
#include<string.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
vector<string> splitSequenceOfAddressExpressionsAtCommas(const string& mes);
|
||||
bool isValidMatchExpression(const std::string& s, bool *has_wildcard);
|
||||
bool doesIdMatchExpression(const std::string& id, std::string match_rule);
|
||||
bool doesAddressMatchExpressions(Address &address,
|
||||
std::vector<AddressExpression>& address_expressions,
|
||||
bool *used_wildcard,
|
||||
bool *filtered_out,
|
||||
bool *required_found,
|
||||
bool *required_failed);
|
||||
|
||||
bool isValidMatchExpression(const string& s, bool *has_wildcard)
|
||||
{
|
||||
string me = s;
|
||||
|
||||
// Examples of valid match expressions:
|
||||
// 12345678
|
||||
// *
|
||||
// 123*
|
||||
// !12345677
|
||||
// 2222222*
|
||||
// !22222222
|
||||
// We also accept an secondary libmbus address:
|
||||
// 100002842941011B
|
||||
|
||||
// A match expression cannot be empty.
|
||||
if (me.length() == 0) return false;
|
||||
|
||||
// An me can be filtered out with an exclamation mark first.
|
||||
if (me.front() == '!') me.erase(0, 1);
|
||||
|
||||
// More than one negation is not allowed.
|
||||
if (me.front() == '!') return false;
|
||||
|
||||
// A match expression cannot be only a negation mark.
|
||||
if (me.length() == 0) return false;
|
||||
|
||||
int count = 0;
|
||||
// Some non-compliant meters have full hex in the id,
|
||||
// but according to the standard there should only be bcd here...
|
||||
// We accept hex anyway.
|
||||
while (me.length() > 0 &&
|
||||
((me.front() >= '0' && me.front() <= '9') ||
|
||||
(me.front() >= 'A' && me.front() <= 'F') ||
|
||||
(me.front() >= 'a' && me.front() <= 'f')))
|
||||
{
|
||||
me.erase(0,1);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (me.length() == 0 && count == 16)
|
||||
{
|
||||
// A secondary libmbus address: 100002842941011B
|
||||
// Strictly speaking the leading 8 digits should be bcd,
|
||||
// but we accept hex as well.
|
||||
*has_wildcard = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wildcard_used = false;
|
||||
// An expression can end with a *
|
||||
if (me.length() > 0 && me.front() == '*')
|
||||
{
|
||||
me.erase(0,1);
|
||||
wildcard_used = true;
|
||||
if (has_wildcard) *has_wildcard = true;
|
||||
}
|
||||
|
||||
// Now we should have eaten the whole expression.
|
||||
if (me.length() > 0) return false;
|
||||
|
||||
// Check the length of the matching bcd/hex
|
||||
// If no wildcard is used, then the match expression must be exactly 8 digits.
|
||||
if (!wildcard_used) return count == 8;
|
||||
|
||||
// If wildcard is used, then the match expressions must be 7 or less digits,
|
||||
// even zero is allowed which means a single *, which matches any bcd/hex id.
|
||||
return count <= 7;
|
||||
}
|
||||
|
||||
vector<string> splitSequenceOfAddressExpressionsAtCommas(const string& mes)
|
||||
{
|
||||
vector<string> r;
|
||||
bool eof, err;
|
||||
vector<uchar> v (mes.begin(), mes.end());
|
||||
auto i = v.begin();
|
||||
|
||||
for (;;) {
|
||||
auto id = eatTo(v, i, ',', 64, &eof, &err);
|
||||
if (err) break;
|
||||
trimWhitespace(&id);
|
||||
if (id == "ANYID") id = "*";
|
||||
r.push_back(id);
|
||||
if (eof) break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool isValidSequenceOfAddressExpressions(const string& mes)
|
||||
{
|
||||
vector<string> v = splitSequenceOfAddressExpressionsAtCommas(mes);
|
||||
|
||||
for (string me : v)
|
||||
{
|
||||
AddressExpression ae;
|
||||
if (!ae.parse(me)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<AddressExpression> splitAddressExpressions(const string &aes)
|
||||
{
|
||||
vector<string> v = splitSequenceOfAddressExpressionsAtCommas(aes);
|
||||
|
||||
vector<AddressExpression> r;
|
||||
|
||||
for (string me : v)
|
||||
{
|
||||
AddressExpression ae;
|
||||
if (ae.parse(me))
|
||||
{
|
||||
r.push_back(ae);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool doesIdMatchExpression(const string& s, string match)
|
||||
{
|
||||
string id = s;
|
||||
if (id.length() == 0) return false;
|
||||
|
||||
// Here we assume that the match expression has been
|
||||
// verified to be valid.
|
||||
bool can_match = true;
|
||||
|
||||
// Now match bcd/hex until end of id, or '*' in match.
|
||||
while (id.length() > 0 && match.length() > 0 && match.front() != '*')
|
||||
{
|
||||
if (id.front() != match.front())
|
||||
{
|
||||
// We hit a difference, it cannot match.
|
||||
can_match = false;
|
||||
break;
|
||||
}
|
||||
id.erase(0,1);
|
||||
match.erase(0,1);
|
||||
}
|
||||
|
||||
bool wildcard_used = false;
|
||||
if (match.length() && match.front() == '*')
|
||||
{
|
||||
wildcard_used = true;
|
||||
match.erase(0,1);
|
||||
}
|
||||
|
||||
if (can_match)
|
||||
{
|
||||
// Ok, now the match expression should be empty.
|
||||
// If wildcard is true, then the id can still have digits,
|
||||
// otherwise it must also be empty.
|
||||
if (wildcard_used)
|
||||
{
|
||||
can_match = match.length() == 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
can_match = match.length() == 0 && id.length() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
return can_match;
|
||||
}
|
||||
|
||||
bool hasWildCard(const string& mes)
|
||||
{
|
||||
return mes.find('*') != string::npos;
|
||||
}
|
||||
|
||||
bool AddressExpression::match(const std::string &i, uint16_t m, uchar v, uchar t)
|
||||
{
|
||||
if (!(mfct == 0xffff || mfct == m)) return false;
|
||||
if (!(version == 0xff || version == v)) return false;
|
||||
if (!(type == 0xff || type == t)) return false;
|
||||
if (!doesIdMatchExpression(i, id)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AddressExpression::trimToIdentity(IdentityMode im, Address &a)
|
||||
{
|
||||
switch (im)
|
||||
{
|
||||
case IdentityMode::FULL:
|
||||
id = a.id;
|
||||
mfct = a.mfct;
|
||||
version = a.version;
|
||||
type = a.type;
|
||||
required = true;
|
||||
break;
|
||||
case IdentityMode::ID_MFCT:
|
||||
id = a.id;
|
||||
mfct = a.mfct;
|
||||
version = 0xff;
|
||||
type = 0xff;
|
||||
required = true;
|
||||
break;
|
||||
case IdentityMode::ID:
|
||||
id = a.id;
|
||||
mfct = 0xffff;
|
||||
version = 0xff;
|
||||
type = 0xff;
|
||||
required = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool AddressExpression::parse(const string &in)
|
||||
{
|
||||
string s = in;
|
||||
// Example: 12345678
|
||||
// or 12345678.M=PII.T=1B.V=01
|
||||
// or 1234*
|
||||
// or 1234*.M=PII
|
||||
// or 1234*.V=01
|
||||
// or 12 // mbus primary
|
||||
// or 0 // mbus primary
|
||||
// or 250.MPII.V01.T1B // mbus primary
|
||||
// or !12345678
|
||||
// or !*.M=ABC
|
||||
// or libmbus secondary style:
|
||||
// 123456782941011B
|
||||
id = "";
|
||||
mbus_primary = false;
|
||||
mfct = 0xffff;
|
||||
type = 0xff;
|
||||
version = 0xff;
|
||||
filter_out = false;
|
||||
|
||||
if (s.size() == 0) return false;
|
||||
|
||||
if (s.size() > 1 && s[0] == '!')
|
||||
{
|
||||
filter_out = true;
|
||||
s = s.substr(1);
|
||||
// Double ! not allowed.
|
||||
if (s.size() > 1 && s[0] == '!') return false;
|
||||
}
|
||||
vector<string> parts = splitString(s, '.');
|
||||
|
||||
assert(parts.size() > 0);
|
||||
|
||||
id = parts[0];
|
||||
if (!isValidMatchExpression(id, &has_wildcard))
|
||||
{
|
||||
// Not a long id, so lets check if it is p0 to p250 for primary mbus ids.
|
||||
if (id.size() < 2) return false;
|
||||
if (id[0] != 'p') return false;
|
||||
for (size_t i=1; i < id.length(); ++i)
|
||||
{
|
||||
if (!isdigit(id[i])) return false;
|
||||
}
|
||||
// All digits good.
|
||||
int v = atoi(id.c_str()+1);
|
||||
if (v < 0 || v > 250) return false;
|
||||
// It is 0-250 which means it is an mbus primary address.
|
||||
mbus_primary = true;
|
||||
}
|
||||
|
||||
if (parts.size() == 1 && id.length() == 16)
|
||||
{
|
||||
// This is a secondary libmbus address.
|
||||
string mfct_hex = id.substr(8,4);
|
||||
string version_hex = id.substr(12,2);
|
||||
string type_hex = id.substr(14,2);
|
||||
id = id.substr(0,8);
|
||||
|
||||
vector<uchar> data;
|
||||
bool ok = hex2bin(mfct_hex.c_str(), &data);
|
||||
if (!ok) return false;
|
||||
if (data.size() != 2) return false;
|
||||
mfct = data[1] << 8 | data[0];
|
||||
|
||||
data.clear();
|
||||
ok = hex2bin(version_hex.c_str(), &data);
|
||||
if (!ok) return false;
|
||||
if (data.size() != 1) return false;
|
||||
version = data[0];
|
||||
|
||||
data.clear();
|
||||
ok = hex2bin(type_hex.c_str(), &data);
|
||||
if (!ok) return false;
|
||||
if (data.size() != 1) return false;
|
||||
type = data[0];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
for (size_t i=1; i<parts.size(); ++i)
|
||||
{
|
||||
if (parts[i].size() == 4) // V=xy or T=xy
|
||||
{
|
||||
if (parts[i][1] != '=') return false;
|
||||
|
||||
vector<uchar> data;
|
||||
bool ok = hex2bin(&parts[i][2], &data);
|
||||
if (!ok) return false;
|
||||
if (data.size() != 1) return false;
|
||||
|
||||
if (parts[i][0] == 'V')
|
||||
{
|
||||
version = data[0];
|
||||
}
|
||||
else if (parts[i][0] == 'T')
|
||||
{
|
||||
type = data[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (parts[i].size() == 5) // M=xyz
|
||||
{
|
||||
if (parts[i][1] != '=') return false;
|
||||
if (parts[i][0] != 'M') return false;
|
||||
|
||||
bool ok = flagToManufacturer(&parts[i][2], &mfct);
|
||||
if (!ok) return false;
|
||||
}
|
||||
else if (parts[i].size() == 6) // M=abcd explicit hex version
|
||||
{
|
||||
if (parts[i][1] != '=') return false;
|
||||
if (parts[i][0] != 'M') return false;
|
||||
|
||||
vector<uchar> data;
|
||||
bool ok = hex2bin(&parts[i][2], &data);
|
||||
if (!ok) return false;
|
||||
if (data.size() != 2) return false;
|
||||
|
||||
mfct = data[1] << 8 | data[0];
|
||||
if (!ok) return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool flagToManufacturer(const char *s, uint16_t *out_mfct)
|
||||
{
|
||||
if (s[0] == 0 || s[1] == 0 || s[2] == 0 || s[3] != 0) return false;
|
||||
if (s[0] < '@' || s[0] > 'Z' ||
|
||||
s[1] < '@' || s[1] > 'Z' ||
|
||||
s[2] < '@' || s[2] > 'Z') return false;
|
||||
|
||||
*out_mfct = MANFCODE(s[0],s[1],s[2]);
|
||||
return true;
|
||||
}
|
||||
|
||||
string AddressExpression::str()
|
||||
{
|
||||
string s;
|
||||
|
||||
if (filter_out) s = "!";
|
||||
if (required) s = "R";
|
||||
|
||||
s.append(id);
|
||||
if (mfct != 0xffff)
|
||||
{
|
||||
s += ".M="+manufacturerFlag(mfct);
|
||||
}
|
||||
if (version != 0xff)
|
||||
{
|
||||
s += ".V="+tostrprintf("%02x", version);
|
||||
}
|
||||
if (type != 0xff)
|
||||
{
|
||||
s += ".T="+tostrprintf("%02x", type);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
string Address::str()
|
||||
{
|
||||
string s;
|
||||
|
||||
s.append(id);
|
||||
if (mfct != 0xffff)
|
||||
{
|
||||
s += ".M="+manufacturerFlag(mfct);
|
||||
}
|
||||
if (version != 0xff)
|
||||
{
|
||||
s += ".V="+tostrprintf("%02x", version);
|
||||
}
|
||||
if (type != 0xff)
|
||||
{
|
||||
s += ".T="+tostrprintf("%02x", type);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
string Address::concat(std::vector<Address> &addresses)
|
||||
{
|
||||
string s;
|
||||
for (Address& a: addresses)
|
||||
{
|
||||
if (s.size() > 0) s.append(",");
|
||||
s.append(a.str());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
string AddressExpression::concat(std::vector<AddressExpression> &address_expressions)
|
||||
{
|
||||
string s;
|
||||
for (AddressExpression& a: address_expressions)
|
||||
{
|
||||
if (s.size() > 0) s.append(",");
|
||||
s.append(a.str());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
string manufacturerFlag(int m_field) {
|
||||
char a = (m_field/1024)%32+64;
|
||||
char b = (m_field/32)%32+64;
|
||||
char c = (m_field)%32+64;
|
||||
|
||||
string flag;
|
||||
flag += a;
|
||||
flag += b;
|
||||
flag += c;
|
||||
return flag;
|
||||
}
|
||||
|
||||
void Address::decodeMfctFirst(const vector<uchar>::iterator &pos)
|
||||
{
|
||||
mfct = *(pos+1) << 8 | *(pos+0);
|
||||
id = tostrprintf("%02x%02x%02x%02x", *(pos+5), *(pos+4), *(pos+3), *(pos+2));
|
||||
version = *(pos+6);
|
||||
type = *(pos+7);
|
||||
}
|
||||
|
||||
void Address::decodeIdFirst(const vector<uchar>::iterator &pos)
|
||||
{
|
||||
id = tostrprintf("%02x%02x%02x%02x", *(pos+3), *(pos+2), *(pos+1), *(pos+0));
|
||||
mfct = *(pos+5) << 8 | *(pos+4);
|
||||
version = *(pos+6);
|
||||
type = *(pos+7);
|
||||
}
|
||||
|
||||
bool doesTelegramMatchExpressions(std::vector<Address> &addresses,
|
||||
std::vector<AddressExpression>& address_expressions,
|
||||
bool *used_wildcard)
|
||||
{
|
||||
bool match = false;
|
||||
bool filtered_out = false;
|
||||
bool required_found = false; // An R12345678 field was found.
|
||||
bool required_failed = true; // Init to fail, set to true if R is satistifed anywhere.
|
||||
|
||||
for (Address &a : addresses)
|
||||
{
|
||||
if (doesAddressMatchExpressions(a,
|
||||
address_expressions,
|
||||
used_wildcard,
|
||||
&filtered_out,
|
||||
&required_found,
|
||||
&required_failed))
|
||||
{
|
||||
match = true;
|
||||
}
|
||||
// Go through all ids even though there is an early match.
|
||||
// This way we can see if theres an exact match later.
|
||||
}
|
||||
// If any expression triggered a filter out, then the whole telegram does not match.
|
||||
if (filtered_out) match = false;
|
||||
// If a required field was found and it failed....
|
||||
if (required_found && required_failed) match = false;
|
||||
return match;
|
||||
}
|
||||
|
||||
bool doesAddressMatchExpressions(Address &address,
|
||||
vector<AddressExpression>& address_expressions,
|
||||
bool *used_wildcard,
|
||||
bool *filtered_out,
|
||||
bool *required_found,
|
||||
bool *required_failed)
|
||||
{
|
||||
bool found_match = false;
|
||||
bool found_negative_match = false;
|
||||
bool exact_match = false;
|
||||
|
||||
// Goes through all possible match expressions.
|
||||
// If no expression matches, neither positive nor negative,
|
||||
// then the result is false. (ie no match)
|
||||
|
||||
// If more than one positive match is found, and no negative,
|
||||
// then the result is true.
|
||||
|
||||
// If more than one negative match is found, irrespective
|
||||
// if there is any positive matches or not, then the result is false.
|
||||
|
||||
// If a positive match is found, using a wildcard not any exact match,
|
||||
// then *used_wildcard is set to true.
|
||||
|
||||
// If an expression is required and it fails, then the match fails.
|
||||
for (AddressExpression &ae : address_expressions)
|
||||
{
|
||||
bool has_wildcard = ae.has_wildcard;
|
||||
bool is_negative_rule = ae.filter_out;
|
||||
// We currently assume that only a single expression is required, the last one!
|
||||
bool is_required = ae.required;
|
||||
|
||||
if (is_required) *required_found = true;
|
||||
|
||||
bool m = ae.match(address.id, address.mfct, address.version, address.type);
|
||||
|
||||
if (is_negative_rule)
|
||||
{
|
||||
if (m) found_negative_match = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m)
|
||||
{
|
||||
// A match, but the required does not count.
|
||||
if (!is_required)
|
||||
{
|
||||
found_match = true;
|
||||
if (!has_wildcard)
|
||||
{
|
||||
exact_match = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*required_failed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found_negative_match)
|
||||
{
|
||||
*filtered_out = true;
|
||||
return false;
|
||||
}
|
||||
if (found_match)
|
||||
{
|
||||
if (exact_match)
|
||||
{
|
||||
*used_wildcard = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*used_wildcard = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *toString(IdentityMode im)
|
||||
{
|
||||
switch (im)
|
||||
{
|
||||
case IdentityMode::ID: return "id";
|
||||
case IdentityMode::ID_MFCT: return "id-mfct";
|
||||
case IdentityMode::FULL: return "full";
|
||||
case IdentityMode::NONE: return "none";
|
||||
case IdentityMode::INVALID: return "invalid";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
IdentityMode toIdentityMode(const char *s)
|
||||
{
|
||||
if (!strcmp(s,"id")) return IdentityMode::ID;
|
||||
if (!strcmp(s,"id-mfct")) return IdentityMode::ID_MFCT;
|
||||
if (!strcmp(s, "full")) return IdentityMode::FULL;
|
||||
if (!strcmp(s, "none")) return IdentityMode::NONE;
|
||||
return IdentityMode::INVALID;
|
||||
}
|
||||
|
||||
void AddressExpression::clear()
|
||||
{
|
||||
id = "";
|
||||
has_wildcard = false;
|
||||
mbus_primary = false;
|
||||
mfct = 0xffff;
|
||||
version = 0xff;
|
||||
type = 0xff;
|
||||
}
|
||||
|
||||
void AddressExpression::appendIdentity(IdentityMode im,
|
||||
AddressExpression *identity_expression,
|
||||
std::vector<Address> &as,
|
||||
std::vector<AddressExpression> &es)
|
||||
{
|
||||
identity_expression->clear();
|
||||
if (im == IdentityMode::NONE) return;
|
||||
|
||||
// Copy id, id-mfct, id-mfct-v-t to identity_expression from the last address.
|
||||
identity_expression->trimToIdentity(im, as.back());
|
||||
|
||||
// Is this identity expression already in the list of address expressions?
|
||||
if (std::find(es.begin(), es.end(), *identity_expression) == es.end())
|
||||
{
|
||||
// No, then add it at the end.
|
||||
es.push_back(*identity_expression);
|
||||
}
|
||||
}
|
||||
|
||||
bool AddressExpression::operator==(const AddressExpression&ae) const
|
||||
{
|
||||
return id == ae.id &&
|
||||
has_wildcard == ae.has_wildcard&&
|
||||
mbus_primary == ae.mbus_primary &&
|
||||
mfct == ae.mfct &&
|
||||
version == ae.version &&
|
||||
type == ae.type &&
|
||||
filter_out == ae.filter_out;
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Copyright (C) 2017-2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADDRESS_H_
|
||||
#define ADDRESS_H_
|
||||
|
||||
#include "util.h"
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
IdentityMode:
|
||||
|
||||
@ID: The default, only the id groups the meter content.
|
||||
@ID_MFCT: Used when you have two meters with the same id but different manufacturers.
|
||||
@FULL: Used when you want to fully separate meter content on id.mft.v.t
|
||||
@NONE: Do not separate any meters! This might lead to telegrams overwriting each others state.
|
||||
Use this when no state is to be kept in the wmbusmeters object.
|
||||
@INVALID: Cannot parse cmdline.
|
||||
*/
|
||||
enum class IdentityMode
|
||||
{
|
||||
ID,
|
||||
ID_MFCT,
|
||||
FULL,
|
||||
NONE,
|
||||
INVALID
|
||||
};
|
||||
|
||||
const char *toString(IdentityMode im);
|
||||
IdentityMode toIdentityMode(const char *s);
|
||||
|
||||
struct Address
|
||||
{
|
||||
std::string id; // p1 or 12345678 or non-compliant hex: 1234abcd
|
||||
uint16_t mfct {};
|
||||
uchar type {};
|
||||
uchar version {};
|
||||
|
||||
void decodeMfctFirst(const std::vector<uchar>::iterator &pos);
|
||||
void decodeIdFirst(const std::vector<uchar>::iterator &pos);
|
||||
|
||||
std::string str();
|
||||
static std::string concat(std::vector<Address> &addresses);
|
||||
};
|
||||
|
||||
struct AddressExpression
|
||||
{
|
||||
// An address expression is used to select which telegrams to decode for a driver.
|
||||
// An address expression is also used to select a specific meter to poll for data.
|
||||
// Example address: 12345678
|
||||
// Or fully qualified: 12345678.M=PII.T=1b.V=01
|
||||
// which means manufacturer triplet PII, type/media=0x1b, version=0x01
|
||||
// Or wildcards in id: 12*.T=16
|
||||
// which matches all cold water meters whose ids start with 12.
|
||||
// Or negated tests: 12345678.V!=66
|
||||
// which will decode all telegrams from 12345678 except those where the version is 0x66.
|
||||
// Or every telegram which is does not start with 12 and is not from ABB:
|
||||
// !12*.M!=ABB
|
||||
|
||||
std::string id; // p1 or 12345678 or non-compliant hex: 1234abcd
|
||||
bool has_wildcard {}; // The id contains a *
|
||||
bool mbus_primary {}; // Signals that the id is 0-250
|
||||
|
||||
uint16_t mfct { 0xffff }; // If 0xffff then any mfct matches this address.
|
||||
uchar version { 0xff }; // If 0xff then any version matches this address.
|
||||
uchar type { 0xff }; // If 0xff then any type matches this address.
|
||||
|
||||
bool filter_out {}; // Telegrams matching this rule should be filtered out!
|
||||
bool required {}; // If true, then this address expression must be matched!
|
||||
|
||||
AddressExpression() {}
|
||||
AddressExpression(Address &a) : id(a.id), mfct(a.mfct), version(a.version), type(a.type) { }
|
||||
bool operator==(const AddressExpression&) const;
|
||||
void clear();
|
||||
void trimToIdentity(IdentityMode im, Address &a);
|
||||
bool parse(const std::string &s);
|
||||
bool match(const std::string &id, uint16_t mfct, uchar version, uchar type);
|
||||
std::string str();
|
||||
static std::string concat(std::vector<AddressExpression> &address_expressions);
|
||||
static void appendIdentity(IdentityMode im,
|
||||
AddressExpression *identity_expression,
|
||||
std::vector<Address> &as,
|
||||
std::vector<AddressExpression> &es);
|
||||
};
|
||||
|
||||
/**
|
||||
isValidSequenceOfAddressExpressions:
|
||||
|
||||
Valid sequenes look like this:
|
||||
12345678
|
||||
12345678,22334455,34*
|
||||
12*.T=16,!*.M=XYZ
|
||||
!*.V=33
|
||||
*/
|
||||
bool isValidSequenceOfAddressExpressions(const std::string& s);
|
||||
std::vector<AddressExpression> splitAddressExpressions(const std::string &aes);
|
||||
bool flagToManufacturer(const char *s, uint16_t *out_mfct);
|
||||
std::string manufacturerFlag(int m_field);
|
||||
bool doesTelegramMatchExpressions(std::vector<Address> &addresses,
|
||||
std::vector<AddressExpression>& address_expressions,
|
||||
bool *used_wildcard);
|
||||
|
||||
#endif
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace
|
|||
"The total gas consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -53,7 +53,7 @@ namespace
|
|||
"The current gas flow.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -64,7 +64,7 @@ namespace
|
|||
"The current temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
"Date time when previous billing period ended.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
|
@ -87,7 +87,7 @@ namespace
|
|||
"The total gas consumption recorded when the previous billing period ended.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -54,7 +54,7 @@ namespace
|
|||
"Current power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::PowerW)
|
||||
|
@ -65,7 +65,7 @@ namespace
|
|||
"The total energy production recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0E833C"))
|
||||
);
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
"Current power production.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0BAB3C"))
|
||||
);
|
||||
|
@ -85,7 +85,7 @@ namespace
|
|||
"Voltage at phase L1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0AFDC9FC01"))
|
||||
);
|
||||
|
@ -95,7 +95,7 @@ namespace
|
|||
"Voltage at phase L2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0AFDC9FC02"))
|
||||
);
|
||||
|
@ -105,7 +105,7 @@ namespace
|
|||
"Voltage at phase L3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0AFDC9FC03"))
|
||||
);
|
||||
|
@ -124,7 +124,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter on tariff 1.",
|
||||
DEFAULT_PRINT_PROPERTIES, // ,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -136,7 +136,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter on tariff 2.",
|
||||
DEFAULT_PRINT_PROPERTIES, // ,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -148,7 +148,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter on tariff 3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -160,7 +160,7 @@ namespace
|
|||
"The total energy production recorded by this meter on tariff 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("8E10833C"))
|
||||
);
|
||||
|
@ -170,7 +170,7 @@ namespace
|
|||
"The total energy production recorded by this meter on tariff 2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("8E20833C"))
|
||||
);
|
||||
|
@ -180,7 +180,7 @@ namespace
|
|||
"The total energy production recorded by this meter on tariff 3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("8E30833C"))
|
||||
);
|
||||
|
@ -190,7 +190,7 @@ namespace
|
|||
"The maximum demand indicator (maximum 15-min average power consumption recorded this month).",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"",
|
||||
{
|
||||
|
@ -95,7 +95,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -106,7 +106,7 @@ namespace
|
|||
"Heat cost allocation at the most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -118,7 +118,7 @@ namespace
|
|||
"The heat cost allocation at set date #.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -80,7 +80,7 @@ namespace
|
|||
"Water consumption at the # billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -100,7 +100,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -30,16 +30,22 @@ 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);
|
||||
|
||||
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 = "-------------------------------------------------------------------------------";
|
||||
|
@ -59,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) {
|
||||
|
@ -104,6 +110,8 @@ bool DriverDynamic::load(DriverInfo *di, const string &file_name, const char *co
|
|||
}
|
||||
catch (...)
|
||||
{
|
||||
xmqFreeDoc(doc);
|
||||
di->setDynamic(file, NULL);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -111,9 +119,10 @@ 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 = NULL;
|
||||
try
|
||||
{
|
||||
XMQDoc *doc = di.getDynamicDriver();
|
||||
doc = di.getDynamicDriver();
|
||||
assert(doc);
|
||||
|
||||
verbose("(driver) constructing driver %s from already loaded file %s\n",
|
||||
|
@ -125,6 +134,7 @@ DriverDynamic::DriverDynamic(MeterInfo &mi, DriverInfo &di) :
|
|||
}
|
||||
catch(...)
|
||||
{
|
||||
xmqFreeDoc(doc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,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];
|
||||
|
@ -172,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);
|
||||
}
|
||||
|
@ -190,7 +200,7 @@ XMQProceed DriverDynamic::add_detect(XMQDoc *doc, XMQNode *detect, DriverInfo *d
|
|||
mfct.c_str(),
|
||||
line,
|
||||
line);
|
||||
throw 1;
|
||||
return XMQ_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,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)
|
||||
|
@ -217,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);
|
||||
|
@ -260,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);
|
||||
|
||||
|
@ -279,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 == "")
|
||||
|
@ -289,6 +317,7 @@ XMQProceed DriverDynamic::add_field(XMQDoc *doc, XMQNode *field, DriverDynamic *
|
|||
properties,
|
||||
quantity,
|
||||
vif_scaling,
|
||||
dif_signedness,
|
||||
match,
|
||||
display_unit
|
||||
);
|
||||
|
@ -322,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;
|
||||
}
|
||||
|
@ -336,6 +378,8 @@ XMQProceed DriverDynamic::add_match(XMQDoc *doc, XMQNode *match, DriverDynamic *
|
|||
{
|
||||
FieldMatcher *fm = dd->tmp_matcher_;
|
||||
|
||||
if (checked_set_difvifkey(xmqGetString(doc, match, "difvifkey"), fm, dd)) return XMQ_CONTINUE;
|
||||
|
||||
checked_set_measurement_type(xmqGetString(doc, match, "measurement_type"), fm, dd);
|
||||
|
||||
checked_set_vif_range(xmqGetString(doc, match, "vif_range"), fm, dd);
|
||||
|
@ -356,6 +400,61 @@ XMQProceed DriverDynamic::add_combinable(XMQDoc *doc, XMQNode *match, DriverDyna
|
|||
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;
|
||||
}
|
||||
|
||||
string check_driver_name(const char *name, string file)
|
||||
{
|
||||
if (!name)
|
||||
|
@ -541,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;
|
||||
}
|
||||
|
@ -554,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)
|
||||
|
@ -619,6 +745,31 @@ Unit check_display_unit(const char *display_unit_s, DriverDynamic *dd)
|
|||
return u;
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -753,3 +904,118 @@ void checked_add_vif_combinable(const char *vif_combinable_s, FieldMatcher *fm,
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -31,12 +31,17 @@ struct DriverDynamic : public virtual MeterCommonImplementation
|
|||
static XMQProceed add_match(XMQDoc *doc, XMQNode *match, DriverDynamic *dd);
|
||||
static XMQProceed add_combinable(XMQDoc *doc, XMQNode *match, DriverDynamic *dd);
|
||||
|
||||
static XMQProceed add_lookup(XMQDoc *doc, XMQNode *lookup, DriverDynamic *dd);
|
||||
static XMQProceed add_map(XMQDoc *doc, XMQNode *map, DriverDynamic *dd);
|
||||
|
||||
const string &fileName() { return file_name_; }
|
||||
|
||||
private:
|
||||
|
||||
string file_name_;
|
||||
FieldMatcher *tmp_matcher_;
|
||||
Translate::Lookup *tmp_lookup_;
|
||||
Translate::Rule *tmp_rule_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -52,7 +52,7 @@ namespace
|
|||
"Current power consumption at phase 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF01"))
|
||||
);
|
||||
|
@ -62,7 +62,7 @@ namespace
|
|||
"Current power consumption at phase 2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF02"))
|
||||
);
|
||||
|
@ -72,7 +72,7 @@ namespace
|
|||
"Current power consumption at phase 3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF03"))
|
||||
);
|
||||
|
@ -92,7 +92,7 @@ namespace
|
|||
"Calculated sum of power consumption of all phases.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -38,7 +38,7 @@ namespace
|
|||
{
|
||||
setMfctTPLStatusBits(
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xe0))
|
||||
.set(DefaultMessage("OK"))
|
||||
.add(Translate::Map(0x04 ,"RTC_INVALID", TestBit::Set))));
|
||||
|
@ -54,7 +54,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -90,7 +90,7 @@ namespace
|
|||
"Number of times the smoke alarm has triggered.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(SubUnitNr(1))
|
||||
|
@ -121,7 +121,7 @@ namespace
|
|||
"Time the smoke alarm has been removed.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(SubUnitNr(1))
|
||||
|
@ -145,7 +145,7 @@ namespace
|
|||
"Number of times the smoke alarm has been removed.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(SubUnitNr(1))
|
||||
|
@ -169,7 +169,7 @@ namespace
|
|||
"Number of times the test button has been pressed.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(SubUnitNr(1))
|
||||
|
@ -208,7 +208,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"DUST",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x1f),
|
||||
"",
|
||||
{
|
||||
|
@ -228,7 +228,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"BATTERY_VOLTAGE",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x0f00),
|
||||
"",
|
||||
{
|
||||
|
@ -267,7 +267,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"OBSTACLE_DISTANCE",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x700000),
|
||||
"",
|
||||
{
|
||||
|
@ -297,7 +297,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"HEAD_STATUS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff8ff0e0),
|
||||
"OK",
|
||||
{
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffffffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -80,7 +80,7 @@ namespace
|
|||
"Current power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::PowerW)
|
||||
|
@ -91,7 +91,7 @@ namespace
|
|||
"Total volume of heat media.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -102,7 +102,7 @@ namespace
|
|||
"The total energy consumption recorded at the target date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -114,7 +114,7 @@ namespace
|
|||
"The flow temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -125,7 +125,7 @@ namespace
|
|||
"The return temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
|
@ -136,7 +136,7 @@ namespace
|
|||
"The external temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -147,7 +147,7 @@ namespace
|
|||
"How long the meter has been collecting data.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::OperatingTime)
|
||||
|
@ -167,7 +167,7 @@ namespace
|
|||
"Battery voltage.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -80,7 +80,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"",
|
||||
{
|
||||
|
@ -101,7 +101,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -112,7 +112,7 @@ namespace
|
|||
"Power measured by this meter at the moment.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::AutoSigned,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -123,7 +123,7 @@ namespace
|
|||
"The total energy backward (production) recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -135,7 +135,7 @@ namespace
|
|||
"The reactive total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Reactive_Energy,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FB8275"))
|
||||
);
|
||||
|
@ -145,7 +145,7 @@ namespace
|
|||
"The total reactive energy backward (production) recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Reactive_Energy,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(DifVifKey("04FB82F53C"))
|
||||
|
@ -177,7 +177,7 @@ namespace
|
|||
"Amperage at phase L1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDD9FC01"))
|
||||
);
|
||||
|
@ -187,7 +187,7 @@ namespace
|
|||
"Amperage at phase L2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDD9FC02"))
|
||||
);
|
||||
|
@ -197,7 +197,7 @@ namespace
|
|||
"Amperage at phase L3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDD9FC03"))
|
||||
);
|
||||
|
@ -207,7 +207,7 @@ namespace
|
|||
"Voltage at phase L1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDC8FC01"))
|
||||
);
|
||||
|
@ -217,7 +217,7 @@ namespace
|
|||
"Voltage at phase L2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDC8FC02"))
|
||||
);
|
||||
|
@ -227,7 +227,7 @@ namespace
|
|||
"Voltage at phase L3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04FDC8FC03"))
|
||||
);
|
||||
|
@ -237,7 +237,7 @@ namespace
|
|||
"Frequency in 0.1 Hz",
|
||||
DEFAULT_PRINT_PROPERTIES | PrintProperty::HIDE,
|
||||
Quantity::Frequency,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("02FB2E"))
|
||||
);
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -53,7 +53,7 @@ namespace
|
|||
"The target water consumption recorded at previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -56,7 +56,7 @@ namespace
|
|||
"The energy consumption recorded by this meter at the set date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -68,7 +68,7 @@ namespace
|
|||
"The active power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -79,7 +79,7 @@ namespace
|
|||
"The flow of water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -90,7 +90,7 @@ namespace
|
|||
"The maximum forward flow of water since the last set date?",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -101,7 +101,7 @@ namespace
|
|||
"The forward temperature of the water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -112,7 +112,7 @@ namespace
|
|||
"The return temperature of the water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
|
@ -123,7 +123,7 @@ namespace
|
|||
"The temperature difference forward-return for the water.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::AutoSigned,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::TemperatureDifference)
|
||||
|
@ -134,7 +134,7 @@ namespace
|
|||
"The total amount of water that has passed through this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -145,7 +145,7 @@ namespace
|
|||
"The amount of water that had passed through this meter at the set date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -157,7 +157,7 @@ namespace
|
|||
"The amount of water that has passed through subunit 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -169,7 +169,7 @@ namespace
|
|||
"The amount of water that had passed through the subunit 1 at the set date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -182,7 +182,7 @@ namespace
|
|||
"The current heat cost allocation for subunit 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -194,7 +194,7 @@ namespace
|
|||
"The heat cost allocation for subunit 1 at the target date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -207,7 +207,7 @@ namespace
|
|||
"The current heat cost allocation for subunit 2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -219,7 +219,7 @@ namespace
|
|||
"The heat cost allocation for subunit 2 at the target date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -64,7 +64,7 @@ namespace
|
|||
"Calculated sum of power consumption of all phases.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
"The total energy production recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -87,7 +87,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter on tariff 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -99,7 +99,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter on tariff 2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -111,7 +111,7 @@ namespace
|
|||
"Current power consumption phase 1.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF01"))
|
||||
);
|
||||
|
@ -121,7 +121,7 @@ namespace
|
|||
"Current power consumption phase 2.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF02"))
|
||||
);
|
||||
|
@ -131,7 +131,7 @@ namespace
|
|||
"Current power consumption phase 3.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("04A9FF03"))
|
||||
);
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -98,7 +98,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -109,7 +109,7 @@ namespace
|
|||
"The heat cost allocation at set date #.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -121,7 +121,7 @@ namespace
|
|||
"Deprecated field.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
|
|
@ -42,7 +42,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -53,7 +53,7 @@ namespace
|
|||
"The target water consumption recorded at previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
);
|
||||
|
@ -69,7 +69,7 @@ namespace
|
|||
"Heat cost allocation at the most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(1))
|
||||
|
@ -89,7 +89,7 @@ namespace
|
|||
"Heat cost allocation at the most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(1))
|
||||
|
@ -109,7 +109,7 @@ namespace
|
|||
"Heat cost allocation at the 8 billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(8))
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffffffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -71,7 +71,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -82,7 +82,7 @@ namespace
|
|||
"The total water consumption recorded at the beginning of this month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -104,7 +104,7 @@ namespace
|
|||
"The current flow of water through the meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -115,7 +115,7 @@ namespace
|
|||
"The water temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -127,7 +127,7 @@ namespace
|
|||
"The maximum water temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -139,7 +139,7 @@ namespace
|
|||
"The external temperature outside of the meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -151,7 +151,7 @@ namespace
|
|||
"The maximum flow recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -163,7 +163,7 @@ namespace
|
|||
"The minimum flow recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -175,7 +175,7 @@ namespace
|
|||
"The maximum temperature recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -187,7 +187,7 @@ namespace
|
|||
"The minimum flow recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -199,7 +199,7 @@ namespace
|
|||
"The maximum flow recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -216,7 +216,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"DRY",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x0070),
|
||||
"",
|
||||
{
|
||||
|
@ -243,7 +243,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"REVERSED",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x0380),
|
||||
"",
|
||||
{
|
||||
|
@ -270,7 +270,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"LEAKING",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x1c00),
|
||||
"",
|
||||
{
|
||||
|
@ -297,7 +297,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"BURSTING",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0xe000),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -70,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"))
|
||||
);
|
||||
|
|
|
@ -100,5 +100,5 @@ namespace
|
|||
|
||||
// Test: Wateroo gwfwater 20221031 NOKEY
|
||||
// telegram=|3144E61E31102220010E8C04F47ABE0420452F2F_037410000004133E0000004413FFFFFFFF426CFFFF0F0120012F2F2F2F2F|
|
||||
// {"actuality_duration_s": 16,"battery_y": 0,"id": "20221031","media": "bus/system component","meter": "gwfwater","name": "Wateroo","power_mode": "SAVING","status": "BATTERY_LOW POWER_LOW","target_date": "2128-03-31","target_m3": 4294967.295,"timestamp": "1111-11-11T11:11:11Z","total_m3": 0.062}
|
||||
// {"actuality_duration_s": 16,"battery_y": 0,"id": "20221031","media": "bus/system component","meter": "gwfwater","name": "Wateroo","power_mode": "SAVING","status": "BATTERY_LOW POWER_LOW","target_date": "2128-03-31","target_m3": -0.001,"timestamp": "1111-11-11T11:11:11Z","total_m3": 0.062}
|
||||
// |Wateroo;20221031;0.062;1111-11-11 11:11.11
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -69,7 +69,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -80,7 +80,7 @@ namespace
|
|||
"The heat cost allocation at set date #.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -92,7 +92,7 @@ namespace
|
|||
"Deprecated field.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace
|
|||
{
|
||||
setMfctTPLStatusBits(
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xe0))
|
||||
.set(DefaultMessage("OK"))
|
||||
.add(Translate::Map(0x80 ,"SABOTAGE_ENCLOSURE", TestBit::Set))));
|
||||
|
@ -55,7 +55,7 @@ namespace
|
|||
"The total heating energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -67,7 +67,7 @@ namespace
|
|||
"The date time when the recording was made.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DateTime)
|
||||
|
@ -78,7 +78,7 @@ namespace
|
|||
"The total cooling energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -90,7 +90,7 @@ namespace
|
|||
"Total heating volume of media.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -102,7 +102,7 @@ namespace
|
|||
"Total cooling volume of media.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -114,7 +114,7 @@ namespace
|
|||
"Supply c1 volume.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -126,7 +126,7 @@ namespace
|
|||
"Return c2 volume.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -138,7 +138,7 @@ namespace
|
|||
"The supply t1 pipe temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -150,7 +150,7 @@ namespace
|
|||
"The return t2 pipe temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ReturnTemperature)
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include"meters_common_implementation.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Driver : public virtual MeterCommonImplementation
|
||||
{
|
||||
Driver(MeterInfo &mi, DriverInfo &di);
|
||||
};
|
||||
|
||||
static bool ok = registerDriver([](DriverInfo&di)
|
||||
{
|
||||
di.setName("kampress");
|
||||
di.setDefaultFields("name,id,status,pressure_bar,max_pressure_bar,min_pressure_bar,timestamp");
|
||||
di.setMeterType(MeterType::PressureSensor);
|
||||
di.addLinkMode(LinkMode::C1);
|
||||
di.addDetection(MANUFACTURER_KAM, 0x18, 0x01);
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
});
|
||||
|
||||
Driver::Driver(MeterInfo &mi, DriverInfo &di) : MeterCommonImplementation(mi, di)
|
||||
{
|
||||
addStringFieldWithExtractorAndLookup(
|
||||
"status",
|
||||
"Status and error flags.",
|
||||
DEFAULT_PRINT_PROPERTIES | INCLUDE_TPL_STATUS,
|
||||
FieldMatcher::build()
|
||||
.set(VIFRange::ErrorFlags),
|
||||
{
|
||||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
{ 0x01, "DROP" }, // Unexpected drop in pressure in relation to average pressure.
|
||||
{ 0x02, "SURGE" }, // Unexpected increase in pressure in relation to average pressure.
|
||||
{ 0x04, "HIGH" }, // Average pressure has reached configurable limit. Default 15 bar
|
||||
{ 0x08, "LOW" }, // Average pressure has reached configurable limit. Default 1.5 bar
|
||||
{ 0x10, "TRANSIENT" }, // Pressure changes quickly over short timeperiods. Average is fluctuating.
|
||||
{ 0x20, "COMM_ERROR" } // Cannot measure properly or bad internal communication.
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"pressure",
|
||||
"The measured pressure.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Pressure,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Pressure)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"max_pressure",
|
||||
"The maximum pressure measured during ?.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Pressure,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::Pressure)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"min_pressure",
|
||||
"The minimum pressure measured during ?.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Pressure,
|
||||
VifScaling::Auto,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::Pressure)
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"alfa",
|
||||
"We do not know what this is.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("05FF09"))
|
||||
);
|
||||
|
||||
addNumericFieldWithExtractor(
|
||||
"beta",
|
||||
"We do not know what this is.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("05FF0A"))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Test: Pressing kampress 77000317 NOKEY
|
||||
// telegram=|32442D2C1703007701188D280080E39322DB8F78_22696600126967000269660005FF091954A33A05FF0A99BD823A02FD170800|
|
||||
// {"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.03,"min_pressure_bar":1.02,"alfa_counter":0.001246,"beta_counter":0.000997,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Pressing;77000317;LOW;1.02;1.03;1.02;1111-11-11 11:11.11
|
||||
|
||||
// telegram=|27442D2C1703007701188D280194E393226EC679DE735657_660067006600962B913A21B9423A0800|
|
||||
// {"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.03,"min_pressure_bar":1.02,"alfa_counter":0.001108,"beta_counter":0.000743,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Pressing;77000317;LOW;1.02;1.03;1.02;1111-11-11 11:11.11
|
||||
|
||||
// telegram=|27442D2C1703007701188D289554F295224ED579DE73188A_650066006600E80EA43A6B97A3BA0800|
|
||||
// {"media":"pressure","meter":"kampress","name":"Pressing","id":"77000317","status":"LOW","pressure_bar":1.02,"max_pressure_bar":1.02,"min_pressure_bar":1.01,"alfa_counter":0.001252,"beta_counter":-0.001248,"timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Pressing;77000317;LOW;1.02;1.02;1.01;1111-11-11 11:11.11
|
|
@ -44,7 +44,7 @@ namespace
|
|||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DigitalInput),
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("INPUT_BITS", Translate::Type::IndexToString)
|
||||
.add(Translate::Rule("INPUT_BITS", Translate::MapType::IndexToString)
|
||||
.set(MaskBits(0xffff))
|
||||
.add(Translate::Map(0x11 ,"CLOSED", TestBit::Set))
|
||||
.add(Translate::Map(0x55 ,"OPEN", TestBit::Set))
|
||||
|
@ -58,7 +58,7 @@ namespace
|
|||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ErrorFlags),
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xffff))
|
||||
.set(DefaultMessage("OK"))
|
||||
));
|
||||
|
@ -68,7 +68,7 @@ namespace
|
|||
"How many times the door/window has been opened or closed.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
|
@ -79,7 +79,7 @@ namespace
|
|||
"The current number of counted pulses from counter b.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace
|
|||
{
|
||||
setMfctTPLStatusBits(
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("TPL_STS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("TPL_STS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xe0))
|
||||
.set(DefaultMessage("OK"))
|
||||
.add(Translate::Map(0x40 ,"SABOTAGE_ENCLOSURE", TestBit::Set))));
|
||||
|
@ -60,7 +60,7 @@ namespace
|
|||
"The current number of counted pulses from counter a.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("0EFD3A"))
|
||||
);
|
||||
|
@ -70,7 +70,7 @@ namespace
|
|||
"The current number of counted pulses from counter b.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("8E40FD3A"))
|
||||
);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2021-2022 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
Copyright (C) 2021-2024 Fredrik Öhrström (gpl-3.0-or-later)
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -34,6 +34,7 @@ namespace
|
|||
di.addDetection(MANUFACTURER_LSE, 0x07, 0x18);
|
||||
di.addDetection(MANUFACTURER_LSE, 0x07, 0x16);
|
||||
di.addDetection(MANUFACTURER_LSE, 0x07, 0x17);
|
||||
di.addDetection(MANUFACTURER_LSE, 0x07, 0xd8);
|
||||
di.setConstructor([](MeterInfo& mi, DriverInfo& di){ return shared_ptr<Meter>(new Driver(mi, di)); });
|
||||
});
|
||||
|
||||
|
@ -44,7 +45,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -55,7 +56,7 @@ namespace
|
|||
"The water consumption at the due date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -77,7 +78,7 @@ namespace
|
|||
"The water consumption at the what date?",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -105,7 +106,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -207,3 +208,8 @@ namespace
|
|||
// telegram=|2D4465329933961318067ADA000000_0C13567100004C1300000000426CFFFF02BB560000326CFFFF046D2307A12C|
|
||||
// {"media":"warm water","meter":"lse_07_17","name":"Water","id":"13963399","total_m3":7.156,"due_date_m3":0,"due_date":"2127-15-31","what_date_m3":7,"what_date":"2021-11-30","error_code":"OK","error_date":"2127-15-31","device_date_time":"2021-12-01 07:35","meter_version":"11","timestamp":"1111-11-11T11:11:11Z"}
|
||||
// |Water;13963399;7.156;0;2127-15-31;OK;2127-15-31;2021-12-01 07:35;1111-11-11 11:11.11
|
||||
|
||||
// Test: Water2 lse_07_17 09993623 NOKEY
|
||||
// telegram=|2d44653223369909d8077a80000000046d130aed2B0c13233332004c1351762700426cdf2c326cffff02BB560000|
|
||||
// {"device_date_time": "2023-11-13 10:19","due_date": "2022-12-31","due_date_m3": 277.651,"error_code": "OK","error_date": "2127-15-31","id": "09993623","media": "water","meter": "lse_07_17","name": "Water2","timestamp": "1111-11-11T11:11:11Z","total_m3": 323.323}
|
||||
// |Water2;09993623;323.323;277.651;2022-12-31;OK;2127-15-31;2023-11-13 10:19;1111-11-11 11:11.11
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -66,7 +66,7 @@ namespace
|
|||
"The current heat cost allocation.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -87,7 +87,7 @@ namespace
|
|||
"Heat cost allocation at the most recent billing period date.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::HCA,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::HeatCostAllocation)
|
||||
|
@ -108,7 +108,7 @@ namespace
|
|||
"Duration since last measurement.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::DurationSinceReadout)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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|
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace
|
|||
"The total water consumption recorded at the end of previous year.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -58,7 +58,7 @@ namespace
|
|||
"Date when previous year ended.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::PointInTime,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Date)
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace
|
|||
FieldMatcher::build()
|
||||
.set(DifVifKey("02FF20")),
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0x000f))
|
||||
.set(DefaultMessage("OK"))
|
||||
.add(Translate::Map(0x01 ,"DRY", TestBit::Set))
|
||||
|
@ -60,7 +60,7 @@ namespace
|
|||
"The total water consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -71,7 +71,7 @@ namespace
|
|||
"The total water consumption recorded at the beginning of this month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Volume,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Volume)
|
||||
|
@ -83,7 +83,7 @@ namespace
|
|||
"The water temperature.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::FlowTemperature)
|
||||
|
@ -95,7 +95,7 @@ namespace
|
|||
"The external temperature outside of the meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Any)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -108,7 +108,7 @@ namespace
|
|||
"The lowest external temperature outside of the meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Temperature,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Minimum)
|
||||
.set(VIFRange::ExternalTemperature)
|
||||
|
@ -119,7 +119,7 @@ namespace
|
|||
"The maximum flow recorded during previous period.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Flow,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Maximum)
|
||||
.set(VIFRange::VolumeFlow)
|
||||
|
@ -136,7 +136,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0x000f),
|
||||
"",
|
||||
{
|
||||
|
@ -159,7 +159,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"DRY",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x0070),
|
||||
"",
|
||||
{
|
||||
|
@ -186,7 +186,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"REVERSED",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x0380),
|
||||
"",
|
||||
{
|
||||
|
@ -213,7 +213,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"LEAKING",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0x1c00),
|
||||
"",
|
||||
{
|
||||
|
@ -240,7 +240,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"BURSTING",
|
||||
Translate::Type::IndexToString,
|
||||
Translate::MapType::IndexToString,
|
||||
AlwaysTrigger, MaskBits(0xe000),
|
||||
"",
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace
|
|||
"Et+ the total 3-phase active positive energy.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -61,7 +61,7 @@ namespace
|
|||
"P+ the 3-phase active positive power.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
"Er+ the total 3-phase reactive positive energy.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -89,7 +89,7 @@ namespace
|
|||
"Q+ the 3-phase reactive positive power.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -103,7 +103,7 @@ namespace
|
|||
"Part Et+ the total 3-phase active partial energy.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -117,7 +117,7 @@ namespace
|
|||
"P- the 3-phase active negative power.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -131,7 +131,7 @@ namespace
|
|||
"Part Er+ the total 3-phase reactive partial energy.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -145,7 +145,7 @@ namespace
|
|||
"Q- the 3-phase reactive negative power.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -159,7 +159,7 @@ namespace
|
|||
"PF the power factor.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless),
|
||||
|
@ -174,7 +174,7 @@ namespace
|
|||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ErrorFlags),
|
||||
Translate::Lookup()
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::Type::BitToString)
|
||||
.add(Translate::Rule("ERROR_FLAGS", Translate::MapType::BitToString)
|
||||
.set(MaskBits(0xff))
|
||||
.set(DefaultMessage("OK"))
|
||||
));
|
||||
|
@ -186,7 +186,7 @@ namespace
|
|||
"I1 Amperage for L1 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Amperage)
|
||||
|
@ -198,7 +198,7 @@ namespace
|
|||
"I2 Amperage for L2 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Amperage)
|
||||
|
@ -210,7 +210,7 @@ namespace
|
|||
"I3 Amperage for L3 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Amperage)
|
||||
|
@ -222,7 +222,7 @@ namespace
|
|||
"L1-N Voltage for L1 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -234,7 +234,7 @@ namespace
|
|||
"L2-N Voltagefor L2 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -246,7 +246,7 @@ namespace
|
|||
"L3-N Voltage for L3 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -260,7 +260,7 @@ namespace
|
|||
"P1 Power for L1 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -273,7 +273,7 @@ namespace
|
|||
"P2 Power for L2 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -286,7 +286,7 @@ namespace
|
|||
"P3 Power for L3 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -299,7 +299,7 @@ namespace
|
|||
"Q1 Power for L1 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -312,7 +312,7 @@ namespace
|
|||
"Q2 Power for L2 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -325,7 +325,7 @@ namespace
|
|||
"Q3 Power for L3 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -338,7 +338,7 @@ namespace
|
|||
"PF1 the power factor for L1 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
|
@ -351,7 +351,7 @@ namespace
|
|||
"PF2 the power factor for L2 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
|
@ -364,7 +364,7 @@ namespace
|
|||
"PF3 the power factor for L3 phase.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Dimensionless,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Dimensionless)
|
||||
|
@ -377,7 +377,7 @@ namespace
|
|||
"L1-L2 Voltage between phases.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -389,7 +389,7 @@ namespace
|
|||
"L2-L3 Voltage between phases.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -401,7 +401,7 @@ namespace
|
|||
"L3-L1 Voltage between phases.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Voltage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Voltage)
|
||||
|
@ -413,7 +413,7 @@ namespace
|
|||
"I Neutral amperage.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Amperage,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::Amperage)
|
||||
|
@ -426,7 +426,7 @@ namespace
|
|||
"Frequency in 0.1 Hz",
|
||||
DEFAULT_PRINT_PROPERTIES | PrintProperty::HIDE,
|
||||
Quantity::Frequency,
|
||||
VifScaling::None,
|
||||
VifScaling::None, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(DifVifKey("05FF5A"))
|
||||
);
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -75,7 +75,7 @@ namespace
|
|||
"The total energy backward (production) recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -87,7 +87,7 @@ namespace
|
|||
"The current power consumption.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
@ -98,7 +98,7 @@ namespace
|
|||
"The current power production.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Power,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyPowerVIF)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace
|
|||
{
|
||||
{
|
||||
"ERROR_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger, MaskBits(0xffff),
|
||||
"OK",
|
||||
{
|
||||
|
@ -85,7 +85,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -106,7 +106,7 @@ namespace
|
|||
"The total energy consumption recorded at the last day of the previous month.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(17))
|
||||
|
@ -128,7 +128,7 @@ namespace
|
|||
"The total energy consumption recorded at the last day of the previous year.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(StorageNr(1))
|
||||
|
@ -160,8 +160,11 @@ namespace
|
|||
vector<uchar> v;
|
||||
auto entry = it->second.second;
|
||||
hex2bin(entry.value.substr(0, 8), &v);
|
||||
t->addId(v.begin());
|
||||
std::string info = "*** " + entry.value.substr(0, 8) + " tpl-id (" + t->ids.back() + ")";
|
||||
// FIXME PROBLEM
|
||||
Address a;
|
||||
a.id = tostrprintf("%02x%02x%02x%02x", v[3], v[2], v[1], v[0]);
|
||||
t->addresses.push_back(a);
|
||||
std::string info = "*** " + entry.value.substr(0, 8) + " tpl-id (" + t->addresses.back().id + ")";
|
||||
t->addSpecialExplanation(entry.offset, 4, KindOfData::CONTENT, Understanding::FULL, info.c_str());
|
||||
|
||||
v.clear();
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace
|
|||
"The total energy consumption recorded by this meter.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -89,7 +89,7 @@ namespace
|
|||
"The total energy consumption recorded at key (billing) date",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -121,7 +121,7 @@ namespace
|
|||
info,
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Energy,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::AnyEnergyVIF)
|
||||
|
@ -136,7 +136,7 @@ namespace
|
|||
"The time between the measurement and the sending of this telegram.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::Instantaneous)
|
||||
.set(VIFRange::ActualityDuration)
|
||||
|
@ -147,7 +147,7 @@ namespace
|
|||
"How long the meter has been in an error state and unable to measure values, while powered up.",
|
||||
DEFAULT_PRINT_PROPERTIES,
|
||||
Quantity::Time,
|
||||
VifScaling::Auto,
|
||||
VifScaling::Auto, DifSignedness::Signed,
|
||||
FieldMatcher::build()
|
||||
.set(MeasurementType::AtError)
|
||||
.set(VIFRange::OnTime)
|
||||
|
|
|
@ -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"))
|
||||
);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"))
|
||||
));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
{
|
||||
|
|
|
@ -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"))
|
||||
);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
@ -135,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)
|
||||
{
|
||||
|
@ -313,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;
|
||||
|
@ -401,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;
|
||||
|
@ -448,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
|
||||
|
@ -754,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());
|
||||
|
@ -772,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)
|
||||
|
@ -793,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 ||
|
||||
|
@ -822,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);
|
||||
|
@ -840,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);
|
||||
|
@ -850,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);
|
||||
|
@ -862,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;
|
||||
|
@ -880,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;
|
||||
|
@ -894,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
|
||||
|
|
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -381,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);
|
||||
|
@ -561,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,
|
||||
|
|
|
@ -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" },
|
||||
};
|
||||
|
|
14
src/main.cc
14
src/main.cc
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
399
src/meters.cc
399
src/meters.cc
|
@ -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.
|
||||
|
@ -1627,6 +1678,7 @@ FieldInfo::FieldInfo(int index,
|
|||
Quantity xuantity,
|
||||
Unit display_unit,
|
||||
VifScaling vif_scaling,
|
||||
DifSignedness dif_signedness,
|
||||
double scale,
|
||||
FieldMatcher matcher,
|
||||
string help,
|
||||
|
@ -1643,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),
|
||||
|
@ -1744,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());
|
||||
|
||||
|
@ -1791,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 = "";
|
||||
|
@ -1853,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 != "")
|
||||
|
@ -1941,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);
|
||||
|
@ -2093,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;
|
||||
}
|
||||
|
||||
|
@ -2165,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;
|
||||
|
@ -2355,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)
|
||||
|
@ -2588,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)
|
||||
|
@ -2705,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),
|
||||
|
@ -2720,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)
|
||||
|
@ -2842,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)
|
||||
|
@ -2856,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)
|
||||
|
@ -2870,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)
|
||||
|
@ -2932,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)
|
||||
|
@ -2946,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)
|
||||
|
@ -2961,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)
|
||||
|
@ -2977,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)
|
||||
|
@ -2992,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)
|
||||
|
@ -3007,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)
|
||||
|
@ -3021,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)
|
||||
|
@ -3035,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)
|
||||
|
@ -3048,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)
|
||||
|
@ -3063,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)
|
||||
|
@ -3077,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)
|
||||
|
@ -3091,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)
|
||||
|
@ -3108,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 "?";
|
||||
|
@ -3120,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)
|
||||
|
|
58
src/meters.h
58
src/meters.h
|
@ -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;
|
||||
|
|
|
@ -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_ {};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,13 +38,13 @@ using namespace std;
|
|||
bool verbose_ = false;
|
||||
|
||||
#define LIST_OF_TESTS \
|
||||
X(dynamic_loading)\
|
||||
X(addresses) \
|
||||
X(dynamic_loading) \
|
||||
X(crc) \
|
||||
X(dvparser) \
|
||||
X(devices) \
|
||||
X(linkmodes) \
|
||||
X(ids) \
|
||||
X(addresses) \
|
||||
X(kdf) \
|
||||
X(periods) \
|
||||
X(device_parsing) \
|
||||
|
@ -423,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)
|
||||
{
|
||||
|
@ -437,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)
|
||||
|
@ -495,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)
|
||||
|
@ -510,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)
|
||||
|
@ -1229,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))
|
||||
|
@ -1247,7 +1401,7 @@ void test_translate()
|
|||
{
|
||||
{
|
||||
"FLOW_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger,
|
||||
MaskBits(0x3f),
|
||||
"OOOK",
|
||||
|
@ -1266,7 +1420,7 @@ void test_translate()
|
|||
{
|
||||
{
|
||||
"NO_FLAGS",
|
||||
Translate::Type::BitToString,
|
||||
Translate::MapType::BitToString,
|
||||
AlwaysTrigger,
|
||||
MaskBits(0x03),
|
||||
"OK",
|
||||
|
@ -2164,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());
|
||||
|
@ -2215,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);
|
||||
|
||||
|
@ -2399,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);
|
||||
|
||||
|
@ -2449,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);
|
||||
|
||||
|
|
|
@ -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), "", { } };
|
||||
|
|
|
@ -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
|
||||
|
|
263
src/util.cc
263
src/util.cc
|
@ -654,244 +654,6 @@ bool isValidAlias(const string& alias)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool isValidMatchExpression(const string& s, bool non_compliant)
|
||||
{
|
||||
string me = s;
|
||||
|
||||
// Examples of valid match expressions:
|
||||
// 12345678
|
||||
// *
|
||||
// 123*
|
||||
// !12345677
|
||||
// 2222222*
|
||||
// !22222222
|
||||
|
||||
// A match expression cannot be empty.
|
||||
if (me.length() == 0) return false;
|
||||
|
||||
// An me can be negated with an exclamation mark first.
|
||||
if (me.front() == '!') me.erase(0, 1);
|
||||
|
||||
// A match expression cannot be only a negation mark.
|
||||
if (me.length() == 0) return false;
|
||||
|
||||
int count = 0;
|
||||
if (non_compliant)
|
||||
{
|
||||
// Some non-compliant meters have full hex in the id,
|
||||
// but according to the standard there should only be bcd here...
|
||||
while (me.length() > 0 &&
|
||||
((me.front() >= '0' && me.front() <= '9') ||
|
||||
(me.front() >= 'a' && me.front() <= 'f')))
|
||||
{
|
||||
me.erase(0,1);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// But compliant meters use only a bcd subset.
|
||||
while (me.length() > 0 &&
|
||||
(me.front() >= '0' && me.front() <= '9'))
|
||||
{
|
||||
me.erase(0,1);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
bool wildcard_used = false;
|
||||
// An expression can end with a *
|
||||
if (me.length() > 0 && me.front() == '*')
|
||||
{
|
||||
me.erase(0,1);
|
||||
wildcard_used = 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;
|
||||
}
|
||||
|
||||
bool isValidMatchExpressions(const string& mes, bool non_compliant)
|
||||
{
|
||||
vector<string> v = splitMatchExpressions(mes);
|
||||
|
||||
for (string me : v)
|
||||
{
|
||||
if (!isValidMatchExpression(me, non_compliant)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isValidId(const string& id, bool accept_non_compliant)
|
||||
{
|
||||
|
||||
for (size_t i=0; i<id.length(); ++i)
|
||||
{
|
||||
if (id[i] >= '0' && id[i] <= '9') continue;
|
||||
if (accept_non_compliant)
|
||||
{
|
||||
if (id[i] >= 'a' && id[i] <= 'f') continue;
|
||||
if (id[i] >= 'A' && id[i] <= 'F') continue;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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 doesIdsMatchExpressions(vector<string> &ids, vector<string>& mes, bool *used_wildcard)
|
||||
{
|
||||
bool match = false;
|
||||
for (string &id : ids)
|
||||
{
|
||||
if (doesIdMatchExpressions(id, mes, used_wildcard))
|
||||
{
|
||||
match = true;
|
||||
}
|
||||
// Go through all ids even though there is an early match.
|
||||
// This way we can see if theres an exact match later.
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
bool doesIdMatchExpressions(const string& id, vector<string>& mes, bool *used_wildcard)
|
||||
{
|
||||
bool found_match = false;
|
||||
bool found_negative_match = false;
|
||||
bool exact_match = false;
|
||||
*used_wildcard = 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.
|
||||
|
||||
for (string me : mes)
|
||||
{
|
||||
bool has_wildcard = hasWildCard(me);
|
||||
bool is_negative_rule = (me.length() > 0 && me.front() == '!');
|
||||
if (is_negative_rule)
|
||||
{
|
||||
me.erase(0, 1);
|
||||
}
|
||||
|
||||
bool m = doesIdMatchExpression(id, me);
|
||||
|
||||
if (is_negative_rule)
|
||||
{
|
||||
if (m) found_negative_match = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m)
|
||||
{
|
||||
found_match = true;
|
||||
if (!has_wildcard)
|
||||
{
|
||||
exact_match = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found_negative_match)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (found_match)
|
||||
{
|
||||
if (exact_match)
|
||||
{
|
||||
*used_wildcard = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*used_wildcard = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
string toIdsCommaSeparated(vector<string> &ids)
|
||||
{
|
||||
string cs;
|
||||
for (string& s: ids)
|
||||
{
|
||||
cs += s;
|
||||
cs += ",";
|
||||
}
|
||||
if (cs.length() > 0) cs.pop_back();
|
||||
return cs;
|
||||
}
|
||||
|
||||
bool isFrequency(const string& fq)
|
||||
{
|
||||
int len = fq.length();
|
||||
|
@ -914,24 +676,6 @@ bool isNumber(const string& fq)
|
|||
return true;
|
||||
}
|
||||
|
||||
vector<string> splitMatchExpressions(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, ',', 16, &eof, &err);
|
||||
if (err) break;
|
||||
trimWhitespace(&id);
|
||||
if (id == "ANYID") id = "*";
|
||||
r.push_back(id);
|
||||
if (eof) break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void incrementIV(uchar *iv, size_t len) {
|
||||
uchar *p = iv+len-1;
|
||||
while (p >= iv) {
|
||||
|
@ -2483,3 +2227,10 @@ const std::string &language()
|
|||
|
||||
return lang_;
|
||||
}
|
||||
|
||||
TestBit toTestBit(const char *s)
|
||||
{
|
||||
if (!strcmp(s, "Set")) return TestBit::Set;
|
||||
if (!strcmp(s, "NotSet")) return TestBit::NotSet;
|
||||
return TestBit::Unknown;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Ładowanie…
Reference in New Issue