splittet reading related stuff into extra file
This commit is contained in:
parent
e140190402
commit
a04c73764e
5 changed files with 429 additions and 29 deletions
44
include/fluksov2.h
Normal file
44
include/fluksov2.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* Replacement for fluksod by directly parsing the fluksometers SPI output
|
||||
*
|
||||
* @package vzlogger
|
||||
* @copyright Copyright (c) 2011, The volkszaehler.org project
|
||||
* @license http://www.gnu.org/licenses/gpl.txt GNU Public License
|
||||
* @author Steffen Vogel <info@steffenvogel.de>
|
||||
*/
|
||||
/*
|
||||
* This file is part of volkzaehler.org
|
||||
*
|
||||
* volkzaehler.org 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
|
||||
* any later version.
|
||||
*
|
||||
* volkzaehler.org 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 volkszaehler.org. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _FLUKSOV2_H_
|
||||
#define _FLUKSOV2_H_
|
||||
|
||||
typedef struct {
|
||||
char *fifo;
|
||||
|
||||
int fd; /* file descriptor of fifo */
|
||||
} meter_handle_fluksov2_t;
|
||||
|
||||
/* forward declarations */
|
||||
struct meter;
|
||||
struct reading;
|
||||
|
||||
int meter_init_fluksov2(struct meter *mtr, list_t options);
|
||||
int meter_open_fluksov2(struct meter *mtr);
|
||||
int meter_close_fluksov2(struct meter *mtr);
|
||||
size_t meter_read_fluksov2(struct meter *mtr, struct reading *rds, size_t n);
|
||||
|
||||
#endif /* _FLUKSOV2_H_ */
|
91
include/reading.h
Normal file
91
include/reading.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* Reading related functions
|
||||
*
|
||||
* @package vzlogger
|
||||
* @copyright Copyright (c) 2011, The volkszaehler.org project
|
||||
* @license http://www.gnu.org/licenses/gpl.txt GNU Public License
|
||||
* @author Steffen Vogel <info@steffenvogel.de>
|
||||
*/
|
||||
/*
|
||||
* This file is part of volkzaehler.org
|
||||
*
|
||||
* volkzaehler.org 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
|
||||
* any later version.
|
||||
*
|
||||
* volkzaehler.org 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 volkszaehler.org. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _READING_H_
|
||||
#define _READING_H_
|
||||
|
||||
#include "obis.h"
|
||||
|
||||
#define MAX_IDENTIFIER_LEN 255
|
||||
|
||||
typedef union reading_id {
|
||||
obis_id_t obis;
|
||||
char *string;
|
||||
char *uuid;
|
||||
int channel;
|
||||
} reading_id_t;
|
||||
|
||||
typedef struct reading {
|
||||
double value;
|
||||
struct timeval time;
|
||||
reading_id_t identifier;
|
||||
|
||||
struct reading *next; /* pointer for linked list */
|
||||
} reading_t;
|
||||
|
||||
/* prototypes */
|
||||
|
||||
enum meter_procotol; /* forward declaration */
|
||||
|
||||
/**
|
||||
* Parse two reading identifiers in a given protocol context
|
||||
*
|
||||
* @return result like in strcmp()
|
||||
*/
|
||||
int meter_id_compare(enum meter_procotol, reading_id_t a, reading_id_t b);
|
||||
|
||||
/**
|
||||
* Parse identifier by a given string and protocol
|
||||
*
|
||||
* @param protocol the given protocol context in which the string should be parsed
|
||||
* @param string the string-encoded identifier
|
||||
* @return 0 on success, < 0 on error
|
||||
*/
|
||||
int reading_id_parse(enum meter_procotol protocol, reading_id_t *id, const char *string);
|
||||
|
||||
/**
|
||||
* Print identifier to buffer for debugging/dump
|
||||
*
|
||||
* @return the amount of bytes used in buffer
|
||||
*/
|
||||
size_t reading_id_unparse(enum meter_procotol protocol, reading_id_t identifier, char *buffer, size_t n);
|
||||
|
||||
/**
|
||||
* Converts timeval structure to double
|
||||
*
|
||||
* @param tv the timeval structure
|
||||
* @return the double value
|
||||
*/
|
||||
double tvtod(struct timeval tv);
|
||||
|
||||
/**
|
||||
* Converts double to timeval structure
|
||||
*
|
||||
* @param ts the double value
|
||||
* @return the timeval strucure
|
||||
*/
|
||||
struct timeval dtotv(double ts);
|
||||
|
||||
#endif /* _READING_H_ */
|
145
src/fluksov2.c
Normal file
145
src/fluksov2.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
/**
|
||||
* Parsing SPI output of the new fluksometer
|
||||
*
|
||||
* @package vzlogger
|
||||
* @copyright Copyright (c) 2011, The volkszaehler.org project
|
||||
* @license http://www.gnu.org/licenses/gpl.txt GNU Public License
|
||||
* @author Steffen Vogel <info@steffenvogel.de>
|
||||
*/
|
||||
/*
|
||||
* This file is part of volkzaehler.org
|
||||
*
|
||||
* volkzaehler.org 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
|
||||
* any later version.
|
||||
*
|
||||
* volkzaehler.org 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 volkszaehler.org. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "meter.h"
|
||||
#include "fluksov2.h"
|
||||
#include "options.h"
|
||||
|
||||
int meter_init_fluksov2(meter_t *mtr, list_t options) {
|
||||
meter_handle_fluksov2_t *handle = &mtr->handle.fluksov2;
|
||||
|
||||
char *fifo;
|
||||
if (options_lookup_string(options, "fifo", &fifo) == SUCCESS) {
|
||||
handle->fifo = strdup(fifo);
|
||||
}
|
||||
else {
|
||||
handle->fifo = "/var/run/spid/delta/out";
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int meter_open_fluksov2(meter_t *mtr) {
|
||||
meter_handle_fluksov2_t *handle = &mtr->handle.fluksov2;
|
||||
|
||||
/* open port */
|
||||
handle->fd = open(handle->fifo, O_RDONLY);
|
||||
|
||||
if (handle->fd < 0) {
|
||||
print(log_error, "open(%s): %s", mtr, handle->fifo, strerror(errno));
|
||||
return ERR;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int meter_close_fluksov2(meter_t *mtr) {
|
||||
meter_handle_fluksov2_t *handle = &mtr->handle.fluksov2;
|
||||
|
||||
return close(handle->fd); /* close fifo */
|
||||
}
|
||||
|
||||
size_t read_line(int fd, char *buffer, size_t n) {
|
||||
int r; /* return code of read() */
|
||||
int e = 0; /* end of line? */
|
||||
int i = 0; /* iterator for buffer */
|
||||
char c; /* character read */
|
||||
|
||||
while (i < n) {
|
||||
r = read(fd, &c, 1); /* read byte-per-byte, to identify a line break */
|
||||
|
||||
if (r < 0) { /* an error occured, pass through to caller */
|
||||
return r;
|
||||
}
|
||||
else if (r == 1) { /* successful read */
|
||||
switch (c) {
|
||||
case '\n': /* line delimiter */
|
||||
case '\r':
|
||||
end++;
|
||||
if (end == 2) {
|
||||
return i; /* line end after "\n\r" */
|
||||
}
|
||||
else {
|
||||
break; /* wait for second delimiter */
|
||||
}
|
||||
|
||||
default: /* normal character */
|
||||
buffer[i] = c;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t meter_read_fluksov2(meter_t *mtr, reading_t rds[], size_t n) {
|
||||
meter_handle_fluksov2_t *handle = &mtr->handle.fluksov2;
|
||||
|
||||
char line[64];
|
||||
size_t i = 0; /* number of readings */
|
||||
size_t h = 0; /* sensor numer */
|
||||
|
||||
int r = read_line(handle->fd, line, 64); /* blocking read of a complete line */
|
||||
if (r <= 0) {
|
||||
print(log_error, "read(%s): %s", mtr, handle->fifo, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *time_str = strtok(line, " \t"); /* first token is the timestamp */
|
||||
struct timeval time = {
|
||||
.tv_sec = strtoq(time_str, NULL, 10)
|
||||
.tv_usec = 0 /* no millisecond resolution available */
|
||||
};
|
||||
|
||||
for (int j = 0; j < 3 && i < n; j++) {
|
||||
char *tok = strtok(NULL, " \t");
|
||||
if (tok == NULL) {
|
||||
return i;
|
||||
}
|
||||
|
||||
switch (j) {
|
||||
case 0: /* id (integer) */
|
||||
break; /* just ignore */
|
||||
|
||||
case 1: /* consumption (Wh) */
|
||||
rds[i].identifier.channel = i;
|
||||
rds[i].time = time;
|
||||
rds[i].value = strtod(tok, NULL);
|
||||
i++;
|
||||
|
||||
case 2: /* power (W) */
|
||||
j = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
45
src/meter.c
45
src/meter.c
|
@ -24,9 +24,7 @@
|
|||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "meter.h"
|
||||
#include "options.h"
|
||||
|
@ -39,6 +37,7 @@ static const meter_details_t protocols[] = {
|
|||
METER_DETAIL(file, "Read from file (ex. 1-Wire sensors via OWFS)", 32, TRUE),
|
||||
//METER_DETAIL(exec, "Read from program (ex. 1-Wire sensors via digitemp)", 32, TRUE),
|
||||
METER_DETAIL(random, "Random walk", 1, TRUE),
|
||||
METER_DETAIL(fluksov2, "Read from onboard SPI of a Flukso v2", 16, FALSE),
|
||||
METER_DETAIL(s0, "S0 on RS232", 1, TRUE),
|
||||
METER_DETAIL(d0, "Plaintext protocol (DIN EN 62056-21)", 32, FALSE),
|
||||
#ifdef SML_SUPPORT
|
||||
|
@ -64,16 +63,30 @@ int meter_init(meter_t *mtr, list_t options) {
|
|||
}
|
||||
|
||||
/* interval */
|
||||
mtr->interval = 10;
|
||||
mtr->interval = -1; /* indicates unknown interval */
|
||||
if (options_lookup_int(options, "interval", &mtr->interval) == ERR_INVALID_TYPE) {
|
||||
print(log_error, "Invalid type for interval", mtr);
|
||||
return ERR;
|
||||
}
|
||||
|
||||
const meter_details_t *details = meter_get_details(mtr->protocol);
|
||||
if (details->periodic == TRUE && mtr->interval < 0) {
|
||||
print(log_error, "Interval has to be positive!", mtr);
|
||||
}
|
||||
|
||||
return details->init_func(mtr, options);
|
||||
}
|
||||
|
||||
int meter_lookup_protocol(const char* name, meter_protocol_t *protocol) {
|
||||
for (const meter_details_t *it = meter_get_protocols(); it != NULL; it++) {
|
||||
if (strcmp(it->name, name) == 0) {
|
||||
*protocol = it->id;
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
int meter_open(meter_t *mtr) {
|
||||
const meter_details_t *details = meter_get_details(mtr->protocol);
|
||||
return details->open_func(mtr);
|
||||
|
@ -93,16 +106,6 @@ const meter_details_t * meter_get_protocols() {
|
|||
return protocols;
|
||||
}
|
||||
|
||||
int meter_lookup_protocol(const char *name, meter_protocol_t *protocol) {
|
||||
for (const meter_details_t *it = protocols; it != NULL; it++) {
|
||||
if (strcmp(it->name, name) == 0) {
|
||||
*protocol = it->id;
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
return ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
const meter_details_t * meter_get_details(meter_protocol_t protocol) {
|
||||
for (const meter_details_t *it = protocols; it != NULL; it++) {
|
||||
if (it->id == protocol) {
|
||||
|
@ -112,19 +115,3 @@ const meter_details_t * meter_get_details(meter_protocol_t protocol) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
double tvtod(struct timeval tv) {
|
||||
return tv.tv_sec + tv.tv_usec / 1e6;
|
||||
}
|
||||
|
||||
struct timeval dtotv(double ts) {
|
||||
double integral;
|
||||
double fraction = modf(ts, &integral);
|
||||
|
||||
struct timeval tv = {
|
||||
.tv_usec = (long int) (fraction * 1e6),
|
||||
.tv_sec = (long int) integral
|
||||
};
|
||||
|
||||
return tv;
|
||||
}
|
||||
|
||||
|
|
133
src/reading.c
Normal file
133
src/reading.c
Normal file
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* Reading related functions
|
||||
*
|
||||
* @package vzlogger
|
||||
* @copyright Copyright (c) 2011, The volkszaehler.org project
|
||||
* @license http://www.gnu.org/licenses/gpl.txt GNU Public License
|
||||
* @author Steffen Vogel <info@steffenvogel.de>
|
||||
*/
|
||||
/*
|
||||
* This file is part of volkzaehler.org
|
||||
*
|
||||
* volkzaehler.org 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
|
||||
* any later version.
|
||||
*
|
||||
* volkzaehler.org 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 volkszaehler.org. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "reading.h"
|
||||
#include "meter.h"
|
||||
|
||||
int reading_id_compare(meter_protocol_t protocol, reading_id_t a, reading_id_t b) {
|
||||
switch (protocol) {
|
||||
case meter_protocol_d0:
|
||||
case meter_protocol_sml:
|
||||
return obis_compare(a.obis, b.obis);
|
||||
|
||||
case meter_protocol_fluksov2:
|
||||
return !(a.channel == b.channel);
|
||||
|
||||
case meter_protocol_file:
|
||||
case meter_protocol_exec:
|
||||
return strcmp(a.string, b.string);
|
||||
|
||||
default:
|
||||
/* no channel id, adding all readings to buffer */
|
||||
return 0; /* equal */
|
||||
}
|
||||
}
|
||||
|
||||
int reading_id_parse(meter_protocol_t protocol, reading_id_t *id, const char *string) {
|
||||
switch (protocol) {
|
||||
case meter_protocol_d0:
|
||||
case meter_protocol_sml:
|
||||
if (obis_parse(string, &id->obis) != SUCCESS) {
|
||||
if (obis_lookup_alias(string, &id->obis) != SUCCESS) {
|
||||
return ERR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case meter_protocol_fluksov2: {
|
||||
char type[13];
|
||||
int channel;
|
||||
|
||||
int ret = sscanf(string, "sensor%u/%12s", &channel, type);
|
||||
if (ret != 2) {
|
||||
return ERR;
|
||||
}
|
||||
|
||||
id->channel = channel + 1; /* increment by 1 to distinguish between +0 and -0 */
|
||||
|
||||
if (strcmp(type, "consumption") == 0) {
|
||||
id->channel *= -1;
|
||||
}
|
||||
else if (strcmp(type, "power") != 0) {
|
||||
return ERR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case meter_protocol_file:
|
||||
case meter_protocol_exec:
|
||||
id->string = strdup(string); // TODO free() elsewhere
|
||||
break;
|
||||
|
||||
default: /* ignore other protocols which do not provide id's */
|
||||
break;
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
size_t reading_id_unparse(meter_protocol_t protocol, reading_id_t id, char *buffer, size_t n) {
|
||||
switch (protocol) {
|
||||
case meter_protocol_d0:
|
||||
case meter_protocol_sml:
|
||||
obis_unparse(id.obis, buffer, n);
|
||||
break;
|
||||
|
||||
case meter_protocol_fluksov2:
|
||||
snprintf(buffer, n, "sensor%u/%s", abs(id.channel) - 1, (id.channel > 0) ? "power" : "consumption");
|
||||
break;
|
||||
|
||||
case meter_protocol_file:
|
||||
case meter_protocol_exec:
|
||||
if (id.string != NULL) {
|
||||
strncpy(buffer, id.string, n);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
|
||||
return strlen(buffer);
|
||||
}
|
||||
|
||||
double tvtod(struct timeval tv) {
|
||||
return tv.tv_sec + tv.tv_usec / 1e6;
|
||||
}
|
||||
|
||||
struct timeval dtotv(double ts) {
|
||||
double integral;
|
||||
double fraction = modf(ts, &integral);
|
||||
|
||||
struct timeval tv = {
|
||||
.tv_usec = (long int) (fraction * 1e6),
|
||||
.tv_sec = (long int) integral
|
||||
};
|
||||
|
||||
return tv;
|
||||
}
|
Loading…
Add table
Reference in a new issue