added ids for Hager eHz

replaced regex parser
This commit is contained in:
Steffen Vogel 2011-11-02 09:16:53 +01:00
parent 933e7507d5
commit f1bc1c5269
2 changed files with 101 additions and 59 deletions

View file

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

View file

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