Skip to content
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

Fix handling of timestamps in Teleinfo component. #2392

Merged
merged 4 commits into from Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 33 additions & 4 deletions esphome/components/teleinfo/teleinfo.cpp
Expand Up @@ -7,14 +7,16 @@ namespace teleinfo {
static const char *const TAG = "teleinfo";

/* Helpers */
static int get_field(char *dest, char *buf_start, char *buf_end, int sep) {
static int get_field(char *dest, char *buf_start, char *buf_end, int sep, int max_len) {
char *field_end;
int len;

field_end = static_cast<char *>(memchr(buf_start, sep, buf_end - buf_start));
if (!field_end)
return 0;
len = field_end - buf_start;
if (len >= max_len)
return len;
strncpy(dest, buf_start, len);
dest[len] = '\0';

Expand Down Expand Up @@ -106,9 +108,22 @@ void TeleInfo::loop() {
* 0xa | Tag | 0x9 | Data | 0x9 | CRC | 0xd
* ^^^^^^^^^^^^^^^^^^^^^^^^^
* Checksum is computed on the above in standard mode.
*
* Note that some Tags may have a timestamp in Standard mode. In this case
* the group would looks like this:
* 0xa | Tag | 0x9 | Timestamp | 0x9 | Data | 0x9 | CRC | 0xd
*
* The DATE tag is a special case. The group looks like this
* 0xa | Tag | 0x9 | Timestamp | 0x9 | 0x9 | CRC | 0xd
*
*/
while ((buf_finger = static_cast<char *>(memchr(buf_finger, (int) 0xa, buf_index_ - 1))) &&
((buf_finger - buf_) < buf_index_)) {
/*
* Make sure timesamp is nullified between each tag as some tags don't
* have a timestamp
*/
timestamp_[0] = '\0';
/* Point to the first char of the group after 0xa */
buf_finger += 1;

Expand All @@ -123,7 +138,7 @@ void TeleInfo::loop() {
continue;

/* Get tag */
field_len = get_field(tag_, buf_finger, grp_end, separator_);
field_len = get_field(tag_, buf_finger, grp_end, separator_, MAX_TAG_SIZE);
if (!field_len || field_len >= MAX_TAG_SIZE) {
ESP_LOGE(TAG, "Invalid tag.");
break;
Expand All @@ -132,8 +147,22 @@ void TeleInfo::loop() {
/* Advance buf_finger to after the tag and the separator. */
buf_finger += field_len + 1;

/* Get value (after next separator) */
field_len = get_field(val_, buf_finger, grp_end, separator_);
/*
* If there is two separators and the tag is not equal to "DATE",
* it means there is a timestamp to read first.
*/
if (std::count(buf_finger, grp_end, separator_) == 2 && strcmp(tag_, "DATE") != 0) {
field_len = get_field(timestamp_, buf_finger, grp_end, separator_, MAX_TIMESTAMP_SIZE);
if (!field_len || field_len >= MAX_TIMESTAMP_SIZE) {
ESP_LOGE(TAG, "Invalid Timestamp");
break;
}

/* Advance buf_finger to after the first data and the separator. */
buf_finger += field_len + 1;
}

field_len = get_field(val_, buf_finger, grp_end, separator_, MAX_VAL_SIZE);
if (!field_len || field_len >= MAX_VAL_SIZE) {
ESP_LOGE(TAG, "Invalid Value");
break;
Expand Down
4 changes: 3 additions & 1 deletion esphome/components/teleinfo/teleinfo.h
Expand Up @@ -11,7 +11,8 @@ namespace teleinfo {
*/
static const uint8_t MAX_TAG_SIZE = 64;
static const uint16_t MAX_VAL_SIZE = 256;
static const uint16_t MAX_BUF_SIZE = 1024;
static const uint16_t MAX_BUF_SIZE = 2048;
static const uint16_t MAX_TIMESTAMP_SIZE = 14;

class TeleInfoListener {
public:
Expand All @@ -36,6 +37,7 @@ class TeleInfo : public PollingComponent, public uart::UARTDevice {
uint32_t buf_index_{0};
char tag_[MAX_TAG_SIZE];
char val_[MAX_VAL_SIZE];
char timestamp_[MAX_TIMESTAMP_SIZE];
enum State {
OFF,
ON,
Expand Down