-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
iec62056: Initial include of iec62056 module #19168
base: master
Are you sure you want to change the base?
Conversation
9005a2b
to
78a80f9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took a quick look
sys/iec62056/iec62056_21.c
Outdated
#define ENABLE_DEBUG 0 | ||
#include "debug.h" | ||
|
||
#define MIN(a, b) (a > b ? b : a) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define MIN(a, b) (a > b ? b : a) | |
#include "macros/utils.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I swear that didn't exist yet back when I wrote this code :)
sys/iec62056/iec62056_21.c
Outdated
time->tm_sec = scn_u32_dec(dataset->value + 10, 2); | ||
time->tm_isdst = dataset->value[12] == 'S'; | ||
|
||
mktime(time); /* Normalize just in case */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mktime(time); /* Normalize just in case */ | |
rtc_tm_normalize(time); /* Normalize just in case */ |
would be a bit cheaper - but I'm not sure if we should really normalize the data here, I wouldn't expect the device to output 'unnormalized' data and normalizing invalid data will just create a very hard to find error. (It's easier to recognize garbage timestamps than timestamps that are somewhat off)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I see what you mean. To be honest I really don't trust smart meters to always output valid timestamp data, hence my idea to normalize it. But maybe this is a case of garbage in -> garbage out.
sys/iec62056/iec62056_obis.c
Outdated
#include "iec62056.h" | ||
#include "iec62056/obis.h" | ||
|
||
#define MAX(a, b) (a > b ? a : b) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#define MAX(a, b) (a > b ? a : b) | |
#include "macros/utils.h"``` |
int res = 0; | ||
char previous_separator = '\0'; | ||
|
||
memset(obis, 255, sizeof(iec62056_obis_t)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why 255 instead of 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to iec62056, the value 0 in an obis is valid data. 255 as value is either reserved, manufacturer specific or signals that the field is unused (in the case of value group F)
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this file is empty, why have it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was useful once, but now it is just there for the doxygen grouping. I'll rework it a bit and remove the file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replaced with a doc.txt in sys/iec62056
for some documentation and a doxygen group.
* @returns negative when parsing failed, zero on success | ||
*/ | ||
int iec62056_21_dataset_parse_register_to_decfrac(const iec62056_21_dataset_t *dataset, | ||
int64_t *mantissa, int64_t *scaling); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really get 128 bit values from this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From IEC62056-21, on the length of the data:
Value: 32 printable characters maximum with the exception of (, ), *, / and !. For decimal values, only points (not commas) shall be used and shall be counted as characters.
Values can be large here, but I don't know if those appear in the wild, I'm severely lacking real world test cases to be honest.
static inline iec62056_obis_t iec62056_obis_init(uint8_t a, uint8_t b, uint8_t c, uint8_t d, | ||
uint8_t e, | ||
uint8_t f) | ||
{ | ||
return (iec62056_obis_t){ a, b, c, d, e, f }; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function seems a bit superfluous
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's mostly a convenience function for initializing the object. I clarified that in the documentation. Let me know if the function should be removed.
return res; | ||
} | ||
|
||
*value = (double)mantissa * pow(10, scaling); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*value = (double)mantissa * pow(10, scaling); | |
*value = (float)mantissa * powf(10, scaling); |
is single precision not enough?
A iec62056_21_dataset_parse_register_to_float()
might be handy if we don't want to pull in soft-float on e.g. Cortex-M4F.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a iec62056_21_dataset_parse_register_to_float()
.
int iec62056_21_dataset_parse_register_to_decfrac(const iec62056_21_dataset_t *dataset, | ||
int64_t *mantissa, int64_t *scaling) | ||
{ | ||
/* parse a string with format '001234.567*kWh' to components */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be made a bit more reusable by moving the number parsing part (01234.567
) to the fmt
module - or just by using sscanf()
for the number
IEC62056_21_STATE_OBIS, | ||
IEC62056_21_STATE_NEXT, | ||
IEC62056_21_STATE_COSEM_OBJECT, | ||
IEC62056_21_STATE_LASTLINE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments would be nice
78a80f9
to
ec9f743
Compare
#include <time.h> | ||
#include <math.h> | ||
|
||
#include "checksum/ucrc16.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does not seem to be used.
const char *telegram, size_t len, bool *skip) | ||
{ | ||
/* find the end of the obis ID */ | ||
const char *obj = memchr(telegram, '(', len); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const char *obj = memchr(telegram, '(', len); | |
const char *obj = memchr(telegram, '(', len); |
bool iec62056_obis_equal(const iec62056_obis_t *first, const iec62056_obis_t *second, | ||
bool include_channel) | ||
{ | ||
return (first->a == second->a) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return (first->a == second->a) && | |
return (first->a == second->a) && |
* | ||
* IEC 62056-21 functions for direct local data exchange of electricity metering. | ||
* | ||
* Function implement protocol telegram parsing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Function implement protocol telegram parsing. | |
* Function implement protocol telegram parsing. |
uint8_t c; /**< Group C: Abstract or physical data item identifier */ | ||
uint8_t d; /**< Group D: Type or result of processing of the physical quantity */ | ||
uint8_t e; /**< Group E: Further processing or classification */ | ||
uint8_t f; /**< Group F: Identifies historical values of data */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uint8_t f; /**< Group F: Identifies historical values of data */ | |
uint8_t f; /**< Group F: Identifies historical values of data */ |
* @brief OBIS identifier struct | ||
*/ | ||
typedef struct { | ||
uint8_t a; /**< Group A: media/energy type */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uint8_t a; /**< Group A: media/energy type */ | |
uint8_t a; /**< Group A: Media/energy type */ |
Or, remove capital from the other group names.
Contribution description
This PR adds a new iec62056 module for reading and parsing smart energy meter data. Main focus at this point is the iec62056-21 sub-specification for local exchange of smart meter data.
The module contributed here can be used as basis for reading DSMR compatible meters exposing a P1 port (IEC62056-21 mode D). I think it can also be used to parse messages from German meters with infrared communication (Mode A through C)
Testing procedure
A test application is provided. Test data is gathered from the local smart meter available here.
Issues/PRs references
None