From b47be0769fcf5c88779fa7085112279e940ed629 Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Thu, 13 Jun 2024 23:55:03 -0700 Subject: [PATCH] Support MeterDiv involvement in Watt calculation. --- docs/protocol-meter-reading.md | 18 ++++++++++++------ .../emporia_vue_utility/emporia_vue_utility.h | 14 ++++++++++---- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/docs/protocol-meter-reading.md b/docs/protocol-meter-reading.md index d01975d..4c80fe5 100644 --- a/docs/protocol-meter-reading.md +++ b/docs/protocol-meter-reading.md @@ -102,7 +102,7 @@ Blank cells have never been seen to be anything other than zero. Some cells have 12 0x01 16 0x25ExportWh~ 20 ~ExportWh0x01 - 24 0x030x220x01 + 24 0x030x22MeterDiv 28 0x020x03 32 0x22EnergyCostUnit 36 0x04 @@ -123,20 +123,26 @@ Bytes 17 to 20, (32 bit int, probably unsigned, LSB) Cumulative watt-hours sent to the grid. Unknown when the value resets, but probably never resets since ESP32 never sends a clock sync to the MGM111 so it likely just rolls over. -#### PowerVal +#### MeterDiv -Bytes 41 and 43 (24 bit signed int, LSB) +Byte 27 -The power being sent or consumed at this moment. This is in watts for me but I know in the V2 payload that there is a `MeterDiv`, which means `PowerVal` might be a multiplication of the real wattage. If V7 also has this behavior then `MeterDiv` must have a value of 1 in my readings. So, `MeterDiv` might be byte 2, 13, 23, or 27. +Used in conjunction with `EnergyCostUnit` and `PowerVal` to calculate the actual wattage. -#### EnergyCostUnit(?) +#### EnergyCostUnit Bytes 34 and 35 LSB Usually `0xE803`, which is `0x03E8` = `1000`. Continuing the V2 theorization that this is the number of watt-hour units per "cost unit". Since people are typically charged per kWh, this value is typically 1000. -This value is not currently used in the code. +#### PowerVal + +Bytes 41 and 43 (24 bit signed int, LSB) + +The power being sent or consumed at this moment. The actual wattage is calculated with the formula: + +`Watts = PowerVal * MeterDiv / (EnergyCostUnit / 1000)` #### Incrementor diff --git a/esphome/components/emporia_vue_utility/emporia_vue_utility.h b/esphome/components/emporia_vue_utility/emporia_vue_utility.h index 8da621f..e8048f5 100644 --- a/esphome/components/emporia_vue_utility/emporia_vue_utility.h +++ b/esphome/components/emporia_vue_utility/emporia_vue_utility.h @@ -82,7 +82,9 @@ class EmporiaVueUtility : public PollingComponent, public uart::UARTDevice { uint32_t import_wh; // Payload Bytes 7 to 10 byte unknown11[6]; // Payload Bytes 11 to 16 uint32_t export_wh; // Payload Bytes 17 to 20 - byte unknown21[13]; // Payload Bytes 21 to 33 + byte unknown21[6]; // Payload Bytes 21 to 26 + uint8_t meter_div; // Payload Byte 27 + byte unknown28[6]; // Payload Bytes 28 to 33 uint16_t cost_unit; // Payload Bytes 34 to 35 byte unknown36[4]; // Payload Bytes 36 to 39 uint32_t watts; // Payload Bytes 40 to 43 : Starts with 0x2A, only use the @@ -351,13 +353,14 @@ class EmporiaVueUtility : public PollingComponent, public uart::UARTDevice { } cost_unit = mr7->cost_unit; - watts = parse_meter_watts_v7(mr7->watts); + watts = parse_meter_watts_v7(mr7); watt_hours = parse_meter_watt_hours_v7(mr7); // Extra debugging of non-zero bytes, only on first packet or if // debug_ is true if ((debug_) || (last_meter_reading == 0)) { ESP_LOGD(TAG, "Meter Cost Unit: %d", cost_unit); + ESP_LOGD(TAG, "Meter Divisor: %d", mr7->meter_div); ESP_LOGD(TAG, "Meter Energy Import Flags: %08x", mr7->import_wh); ESP_LOGD(TAG, "Meter Energy Export Flags: %08x", mr7->export_wh); ESP_LOGD(TAG, "Meter Power Flags: %08x", mr7->watts); @@ -620,10 +623,13 @@ class EmporiaVueUtility : public PollingComponent, public uart::UARTDevice { * * For MGM version 7 and 8 */ - float parse_meter_watts_v7(int32_t watts) { + float parse_meter_watts_v7(struct MeterReadingV7 *mr) { // Read the instant watts value // (it's actually a 24-bit int) - watts >>= 8; + int32_t watts_raw = mr->watts; + watts_raw >>= 8; + float watts = ((float)watts_raw * (float)mr->meter_div) / + ((float)mr->cost_unit / 1000.0); if ((watts >= WATTS_MAX) || (watts < WATTS_MIN)) { ESP_LOGE(TAG, "Unreasonable watts value %d", watts);