added ids for Hager eHz
replaced regex parser
This commit is contained in:
parent
933e7507d5
commit
f1bc1c5269
2 changed files with 101 additions and 59 deletions
|
@ -89,11 +89,7 @@ typedef union {
|
|||
typedef union {
|
||||
unsigned char raw[6];
|
||||
struct {
|
||||
unsigned char media;
|
||||
unsigned char channel;
|
||||
unsigned char indicator;
|
||||
unsigned char mode;
|
||||
unsigned char quantities;
|
||||
unsigned char media, channel, indicator, mode, quantities;
|
||||
unsigned char storage; /* not used in Germany */
|
||||
} groups;
|
||||
} obis_id_t;
|
||||
|
@ -105,10 +101,10 @@ typedef struct {
|
|||
} obis_alias_t;
|
||||
|
||||
/* Prototypes */
|
||||
obis_id_t obis_init(const unsigned char *raw);
|
||||
obis_id_t obis_parse(const char *str);
|
||||
obis_id_t obis_lookup_alias(const char *alias);
|
||||
int obis_unparse(obis_id_t id, char *buffer);
|
||||
obis_id_t * obis_init(obis_id_t *id, const unsigned char *raw);
|
||||
obis_id_t * obis_lookup_alias(const char *alias);
|
||||
int obis_parse(obis_id_t *id, const char *str, size_t n);
|
||||
int obis_unparse(obis_id_t id, char *buffer, size_t n);
|
||||
int obis_compare(obis_id_t a, obis_id_t b);
|
||||
int obis_is_manufacturer_specific(obis_id_t id);
|
||||
int obis_is_null(obis_id_t id);
|
||||
|
|
146
src/obis.c
146
src/obis.c
|
@ -26,100 +26,147 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <regex.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "obis.h"
|
||||
|
||||
#define DC 0xff // wildcard, dont care
|
||||
|
||||
obis_alias_t obis_aliases[] = {
|
||||
/**
|
||||
* 255 is considered as wildcard!
|
||||
*
|
||||
* A B C D E F alias description
|
||||
* A B C D E F alias description
|
||||
* ===================================================================================*/
|
||||
|
||||
/* General */
|
||||
{{{ 1, 0, 12, 7, 0, 255}}, "voltage", ""},
|
||||
{{{ 1, 0, 11, 7, 0, 255}}, "current", ""},
|
||||
{{{ 1, 0, 14, 7, 0, 255}}, "frequency", ""},
|
||||
{{{ 1, 0, 12, 7, 0, 255}}, "powerfactor",""},
|
||||
{{{ 1, 0, 12, 7, DC, DC}}, "voltage", ""},
|
||||
{{{ 1, 0, 32, 7, DC, DC}}, "voltage-l1", ""},
|
||||
{{{ 1, 0, 52, 7, DC, DC}}, "voltage-l2", ""},
|
||||
{{{ 1, 0, 72, 7, DC, DC}}, "voltage-l3", ""},
|
||||
|
||||
{{{ 1, 0, 1, 7, 255, 255}}, "power", "Active Power Instantaneous value Total"},
|
||||
{{{ 1, 0, 21, 7, 255, 255}}, "power-l1", "L1 Active Power Instantaneous value Total"},
|
||||
{{{ 1, 0, 41, 7, 255, 255}}, "power-l2", "L1 Active Power Instantaneous value Total"},
|
||||
{{{ 1, 0, 61, 7, 255, 255}}, "power-l3", "L3 Active Power Instantaneous value Total"},
|
||||
{{{ 1, 0, 11, 7, DC, DC}}, "current", ""},
|
||||
{{{ 1, 0, 31, 7, DC, DC}}, "current-l1", ""},
|
||||
{{{ 1, 0, 51, 7, DC, DC}}, "current-l2", ""},
|
||||
{{{ 1, 0, 71, 7, DC, DC}}, "current-l3", ""},
|
||||
|
||||
{{{ 1, 0, 1, 8, 0, 255}}, "counter", "Active Power Counter Total"},
|
||||
{{{ 1, 0, 14, 7, 0, DC}}, "frequency", ""},
|
||||
{{{ 1, 0, 12, 7, 0, DC}}, "powerfactor", ""},
|
||||
|
||||
{{{ 1, 0, 1, 7, DC, DC}}, "power", "Active Power Instantaneous value Total"},
|
||||
{{{ 1, 0, 21, 7, DC, DC}}, "power-l1", "L1 Active Power Instantaneous value Total"},
|
||||
{{{ 1, 0, 41, 7, DC, DC}}, "power-l2", "L1 Active Power Instantaneous value Total"},
|
||||
{{{ 1, 0, 61, 7, DC, DC}}, "power-l3", "L3 Active Power Instantaneous value Total"},
|
||||
|
||||
{{{ 0, 0, 96, 1, DC, DC}}, "device", "Complete device ID"},
|
||||
{{{ 1, 0, 96, 5, 5, DC}}, "status", "Meter status flag"},
|
||||
|
||||
{{{ 1, 0, 1, 8, DC, DC}}, "counter", "Active Power Counter Total"},
|
||||
{{{ 1, 0, 2, 8, DC, DC}}, "counter-out", "Zählerstand Lieferg."},
|
||||
|
||||
/* Easymeter */
|
||||
{{{ 1, 0, 96, 5, 5, 255}}, "status", "Meter status flag"},
|
||||
|
||||
/* ESYQ3B (Easymeter Q3B) */
|
||||
{{{129, 129, 199, 130, 3, 255}}, "", ""}, // ???
|
||||
{{{ 1, 0, 1, 8, 1, 255}}, "counter-t1", "Active Power Counter Tariff 1"},
|
||||
{{{ 1, 0, 1, 8, 2, 255}}, "counter-t2", "Active Power Counter Tariff 2"},
|
||||
{{{129, 129, 199, 130, 3, DC}}, "esy-?", ""}, // ???
|
||||
{{{ 1, 0, 1, 8, 1, DC}}, "esy-counter-t1", "Active Power Counter Tariff 1"},
|
||||
{{{ 1, 0, 1, 8, 2, DC}}, "esy-counter-t2", "Active Power Counter Tariff 2"},
|
||||
|
||||
/* ESYQ3D (Easymeter Q3D) */
|
||||
{{{ 0, 0, 96, 1, 255, 255}}, "device", "Complete device ID"},
|
||||
{{{ 0, 0, 0, 0, 0, 255}}, "", ""}, // ???
|
||||
|
||||
{{{ 0, 0, 0, 0, 0, DC}}, "esy-?", ""}, // ???
|
||||
|
||||
/* HAG eHZ010C_EHZ1WA02 (Hager eHz) */
|
||||
{{{ 1, 0, 0, 0, 0, DC}}, "hag-id", "Eigentumsnr."},
|
||||
{{{ 1, 0, 96, 50, 0, 0}}, "hag-status", "Netzstatus bitcodiert: Drehfeld, Anlaufschwelle, Energierichtung"},
|
||||
{{{ 1, 0, 96, 50, 0, 1}}, "hag-frequency", "Netz-Periode, hexadezimal (Einheit 1/100 ms)"},
|
||||
{{{ 1, 0, 96, 50, 0, 2}}, "hag-temp", "aktuelle Chiptemperatur, hexadezimal, Einheit °C"},
|
||||
{{{ 1, 0, 96, 50, 0, 3}}, "hag-temp-min", "minimale Chiptemperatur"},
|
||||
{{{ 1, 0, 96, 50, 0, 4}}, "hag-temp-avg", "gemittelte Chiptemperatur"},
|
||||
{{{ 1, 0, 96, 50, 0, 5}}, "hag-temp-max", "maximale Chiptemperatur"},
|
||||
{{{ 1, 0, 96, 50, 0, 6}}, "hag-check", "Kontrollnummer"},
|
||||
{{{ 1, 0, 96, 50, 0, 7}}, "hag-diag", "Diagnose"},
|
||||
|
||||
{} /* stop condition for iterator */
|
||||
};
|
||||
|
||||
obis_id_t obis_init(const unsigned char *raw) {
|
||||
obis_id_t id;
|
||||
|
||||
obis_id_t * obis_init(obis_id_t *id, const unsigned char *raw) {
|
||||
if (raw == NULL) {
|
||||
memset(id.raw, 0, 6); /* initialize with zeros */
|
||||
memset(id->raw, 0, 6); /* initialize with zeros */
|
||||
}
|
||||
else {
|
||||
memcpy(id.raw, raw, 6);
|
||||
memcpy(id->raw, raw, 6);
|
||||
}
|
||||
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
obis_id_t obis_parse(const char *str) {
|
||||
obis_id_t id;
|
||||
regex_t re;
|
||||
regmatch_t matches[7];
|
||||
int obis_parse(obis_id_t *id, const char *str, size_t n) {
|
||||
enum { A = 0, B, C, D, E, F };
|
||||
|
||||
regcomp(&re, "^([0-9])-([0-9]{,2}):([0-9]{,2})\\.([0-9]{,2})\\.([0-9]{,2})(\\[*&][0-9]{,2})?$", REG_EXTENDED | REG_ICASE);
|
||||
// TODO make values A B C optional to allow notations like "1.8.0"
|
||||
char b;
|
||||
int num;
|
||||
int field;
|
||||
|
||||
if (regexec(&re, str, 7, matches, 0) == 0) { /* found string in OBIS notation */
|
||||
for (int i=0; i<6; i++) {
|
||||
if (matches[i+1].rm_so != -1) {
|
||||
id.raw[i] = strtoul(str+matches[i+1].rm_so, NULL, 10);
|
||||
num = b = 0;
|
||||
field = -1;
|
||||
memset(&id->raw, 0xff, 6); /* initialize as wildcard */
|
||||
|
||||
/* format: "A-B:C.D.E[*&]F" */
|
||||
/* fields A, B, E, F are optional */
|
||||
/* fields C & D are mandatory */
|
||||
for (int i = 0; i < n; i++) {
|
||||
b = str[i];
|
||||
|
||||
if (isdigit(b)) {
|
||||
num = (num * 10) + (b - '0'); /* parse digits */
|
||||
}
|
||||
else {
|
||||
if (b == '-' && field < A) { /* end of field A */
|
||||
field = A;
|
||||
}
|
||||
else {
|
||||
id.raw[i] = 0xff; /* default value */
|
||||
else if (b == ':' && field < B) { /* end of field B */
|
||||
field = B;
|
||||
}
|
||||
else if (b == '.' && field < D) { /* end of field C & D*/
|
||||
field = (field < C) ? C : D;
|
||||
}
|
||||
else if ((b == '*' || b == '&') && field == D) { /* end of field E, start of field F */
|
||||
field = E;
|
||||
}
|
||||
else goto error; // TODO lookup aliases
|
||||
|
||||
id->raw[field] = num;
|
||||
num = 0;
|
||||
}
|
||||
}
|
||||
else { /* looking for alias */
|
||||
id = obis_lookup_alias(str);
|
||||
}
|
||||
|
||||
regfree(&re); /* householding */
|
||||
|
||||
return id;
|
||||
/* set last field */
|
||||
id->raw[++field] = num;
|
||||
|
||||
/* fields C & D are mandatory */
|
||||
if (field < D) goto error;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
printf("something unexpected happened (field=%i, b=%c, num=%i): %s:%i!\n", field, b, num, __FUNCTION__, __LINE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
obis_id_t obis_lookup_alias(const char *alias) {
|
||||
obis_id_t nf = obis_init(NULL); /* not found */
|
||||
obis_id_t * obis_lookup_alias(const char *alias) {
|
||||
obis_alias_t *it = obis_aliases;
|
||||
|
||||
do { /* linear search */
|
||||
if (strcmp(it->name, alias) == 0) {
|
||||
return it->id;
|
||||
return &it->id;
|
||||
}
|
||||
} while ((++it)->name);
|
||||
|
||||
return nf;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int obis_unparse(obis_id_t id, char *buffer) {
|
||||
return sprintf(buffer, "%x-%x:%x.%x.%x*%x",
|
||||
int obis_unparse(obis_id_t id, char *buffer, size_t n) {
|
||||
return snprintf(buffer, n, "%i-%i:%i.%i.%i*%i",
|
||||
id.groups.media,
|
||||
id.groups.channel,
|
||||
id.groups.indicator,
|
||||
|
@ -131,7 +178,7 @@ int obis_unparse(obis_id_t id, char *buffer) {
|
|||
|
||||
int obis_compare(obis_id_t a, obis_id_t b) {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (a.raw[i] == b.raw[i] || a.raw[i] == 255 || b.raw[i] == 255 ) {
|
||||
if (a.raw[i] == b.raw[i] || a.raw[i] == 0xff || b.raw[i] == 0xff ) {
|
||||
continue; /* skip on wildcard or equal */
|
||||
}
|
||||
else if (a.raw[i] < b.raw[i]) {
|
||||
|
@ -167,4 +214,3 @@ int obis_is_manufacturer_specific(obis_id_t id) {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue