Git Product home page Git Product logo

weekendwarrior1 / emerald_electricity_advisor Goto Github PK

View Code? Open in Web Editor NEW
32.0 2.0 4.0 321 KB

Collection of code, tools and documentation for data retrieval from your Emerald Electricity Advisor (all reverse engineered)

License: GNU General Public License v3.0

C++ 100.00%
ble emerald esp32 energy-consumption energy-data energy-efficiency energy-monitor emerald-ems arduino esp32-arduino esphome esphome-component

emerald_electricity_advisor's Introduction

This repository is not affiliated with Emerald.

emerald_electricity_advisor

Collection of code, tools and documentation for data retrieval from your Emerald Electricity Advisor (all reverse engineered)

Emerald Electricity Advisor Device

Using the ESPHome Component

The ESPHome component hasn't been merged into esphome yet, but you can use it via external_components

Requirements:

  • An ESP32
  • A configured Emerald Electricity Advisor
  • Electricity Advisor device information:
    • BLE MAC address (can be found on device sticker, by running sketch, or by using an app like nRF Connect once you have disabled the bluetooth of all your smart devices)
    • Connection pairing pin (6 digits you input when setting up your device, also can be found on device sticker (last 6 digits of serial))
    • Your Smart meter pulse rate (eg. 1000 pulses = 1kW/h)
external_components:
  - source: github://WeekendWarrior1/esphome@emerald_ble
    # requires ble_client and ble_tracker because I had to add some small features to authenticate properly
    components: [ ble_client, esp32_ble_tracker, emerald_ble ]

# optional requirement used with daily energy sensor
time:
  - platform: homeassistant
    id: homeassistant_time

esp32_ble_tracker:

ble_client:
  - mac_address: 30:1B:97:01:02:03
    id: emerald_advisor

sensor:
  - platform: emerald_ble
    ble_client_id: emerald_advisor
    power:
      name: "Emerald Power"
    daily_energy:
      name: "Emerald Daily Energy"
    energy:
      name: "Emerald Total Energy"
    battery_level:
      name: "Emerald Battery"
    pairing_code: 123123
    pulses_per_kwh: 1000
    time_id: homeassistant_time # daily energy still works without a time_id, but recommended to include one to properly handle daylight savings, etc.

You can also find a full config here: emerald_ble.yaml

And the component code here: emerald_ble ESPHome Component

Using the Arduino sketch

This sketch simply prints the energy usage and time stamp for the updates sent by the Electricity Advisor, which should be received every 30s.

It's mainly useful to demonstrate that the Electricity Advisor is connectable by a third party device.

Of interest in the sketch is the security configuration required to pair/handshake with the Electricity Advisor, which may limit what BLE technologies, libraries and languages you can use to connect (not every library seems to support secure BLE connections)

Requirements:

  • An ESP32
  • A configured Emerald Electricity Advisor
  • Electricity Advisor device information:
    • BLE MAC address (can be found on device sticker, by running sketch, or by using an app like nRF Connect once you have disabled the bluetooth of all your smart devices)
    • Connection pairing pin (6 digits you input when setting up your device, also can be found on device sticker (last 6 digits of serial))
    • Your Smart meter pulse rate (eg. 1000 pulses = 1kW/h)

Fill in your details at top of esp32_ble_print_data.ino and upload:

static char *BLE_address("30:1b:97:00:00:00"); // lowercase only or else will fail to match
// if your pairing pin starts with 0, eg "024024", set the emerald_pass_key as 24024
static uint32_t emerald_pass_key = 123123;
static float pulses_per_kw = 1000;

Serial Monitor output:

Serial Monitor Example Output

Using the Emerald API

If you would prefer to use the cloud api rather than retrieving real-time data from the Electricity Advisor, please head to api_documentation to learn how to authenticate and retrieve energy data.

Feel free to import the postman collection if you would like to have a play or to investigate the data you can retrieve:

Import (ctrl+o in postman), > link > Enter a URL https://raw.githubusercontent.com/WeekendWarrior1/emerald_electricity_advisor/main/emerald-ems.postman_collection.json > Continue

BLE Documentation

Important BLE services

TIME_SERVICE_UUID: "00001910-0000-1000-8000-00805f9b34fb"
    // Subscribe to notifications on this characteristic for all the Emerald energy information. Data comes back with a descriptive 5 byte command header
    READ_CHAR_UUID: "00002b10-0000-1000-8000-00805f9b34fb"

    // Write commands to this characteristic to change Emerald Advisor settings or retrieve energy data
    WRITE_CHAR_UUID: "00002b11-0000-1000-8000-00805f9b34fb"

Important Emerald Command Headers

getImpulseCmd =                              "0001010500";
getPairingCodeCmd =                          "0001030100";
getEvery30sPowerConsumptionCmd =             "0001020306";
getDeviceTimeCmd =                           "0001010200";
getUpdatedPowerCmd =                         "0001020100";
getEvery30sPowerConsumptionCmdWitninHours =  "0001021308";


// Set pulses_per_kwh, with 2 bytes after the command
// eg. 000101040203E8 <- (1000 in hex = 03E8)
setImpulseCmd =                              "0001010402";
startGettingHistoryCmd =                     "0001020400";
endGettingHistoryCmd =                       "0001020600";
setDeviceTimeCmd =                           "0001010104";
resetCmd =                                   "0001010a00";
// Enable automatic upload of pulses (every 30s)
// eg. 0001020b0101 <- (true in hex = 01)
setAutoUploadStatusCmd =                     "0001020b01";


return30sPowerConsumptionCmd =               "0001020a06";
returnUpdatedPowerCmd =                      "0001020204";
returnEvery30sPowerConsumptionCmd =          "000102050e";
returnImpulseCmd =                           "0001010602";
returnPairingCodeCmd =                       "0001030206";
returnDeviceTimeCmd =                        "0001010304";

Connecting to an Emerald Electricity Advisor over BLE

The Emerald has reasonably strict authentication requirements:

Emerald sent authreq

On an ESP32 I needed to set:

esp_ble_io_cap_t iocap = ESP_IO_CAP_KBDISP;
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(esp_ble_io_cap_t));

uint8_t key_size = 16;
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));

esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND;
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(esp_ble_auth_req_t));

After connecting, the Emerald Advisor will request the passkey from your device, which will depend on your BLE library how you respond:

// arduino callback
class MySecurityCallback : public BLESecurityCallbacks
{
    bool onSecurityRequest() {
        return true;    // Return true if we accept this peer device auth request
    }
    uint32_t onPassKeyRequest() {
        return 123123;
    }
}

// esp-idf
switch (event) {
  case ESP_GAP_BLE_SEC_REQ_EVT: // Return true if we accept this peer device auth request
    esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
    break;
  case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */
    esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, 123123);
    break;
}

Authentication is now complete, so time to enable setAutoUploadStatusCmd:

uint8_t enable_auto_upload[] = {0x00, 0x01, 0x02, 0x0b, 0x01, 0x01};
pRemoteCharacteristic_readingbatchsize->writeValue(enable_auto_upload, sizeof(enable_auto_upload), false);

Subscribe to Emerald Advisor notifications:

pRemoteCharacteristic_time_read = pRemoteService_time->getCharacteristic(CHAR_TIME_READ_UUID);
pRemoteCharacteristic_time_read->registerForNotify(emeraldCommandCallback);

Parse incoming Emerald Advisor notifications:

// incoming data
// pData = [0 1 2 10 6 89 55 105 158 0 12]
// first 5 bytes (0-4) are the Emerald Command Header, which describes the data
uint32_t commandHeader = 0;
for (int i = 0;  i < 5; i++) {
    commandHeader += (pData[i] << (8*(4-i)));
}

// pData [0 1 2 10 6] = 0001020a06, command header return30sPowerConsumptionCmd

// next 4 bytes (5-8) are an oddly formatted timestamp (I'm guessing either for obfuscation or to avoid the Year 2038 unix-timestamp problem)
uint32_t commandDateBin = 0;
for (int i = 5;  i < 9; i++) {
    commandDateBin += (pData[i] << (8*(8-i)));
}
// (6 bits)year + (4 bits)month + (5 bits)days + (5 bits)hours(locale adjusted) + (6 bits)minutes + (6 bits)seconds
uint16_t year = 2000 + (commandDateBin >> 26);  // need to add 2000 to get the correct year
uint8_t month = ((commandDateBin >> 22) & 0b1111);  // month number between 1 - 12
uint8_t days = ((commandDateBin >> 17) & 0b11111); // 1-31
uint8_t hours = ((commandDateBin >> 12) & 0b11111); // 0-23
uint8_t minutes = ((commandDateBin >> 6) & 0b111111); // 0 -59
uint8_t seconds = commandDateBin & 0b111111; // 0 -59

// last 2 bytes (9+10) are the pulses within the time interval window (30s)
uint16_t pulses_within_interval = data[9] << 8;
pulses_within_interval += + data[10];

emerald_electricity_advisor's People

Contributors

weekendwarrior1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

emerald_electricity_advisor's Issues

Incompatible with bluetooth proxy

I have been running this for a while and it has been working flawlessly.

On my ESP that gets Emerald data to HA, I also pick up bluetooth from a couple of Xiaomi temperature sensors. That works well as well.

I am in the process of converting over to use the HA Bluetooth Proxy functionality. I have converted 2 other ESP's to bluetooth proxies and that is working too. When I add the bluetooth_proxy: declaration and attempt to upload, I get the following:-

INFO Reading configuration /config/esphome/esp32-front.yaml...
INFO Detected timezone 'Australia/Sydney'
INFO Generating C++ source...
INFO Compiling app...
Processing esp32-front (board: esp32dev; framework: arduino; platform: platformio/espressif32 @ 5.2.0)
--------------------------------------------------------------------------------
HARDWARE: ESP32 240MHz, 320KB RAM, 4MB Flash
 - toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch3
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
Dependency Graph
|-- AsyncTCP-esphome @ 1.2.2
|-- WiFi @ 2.0.0
|-- FS @ 2.0.0
|-- Update @ 2.0.0
|-- ESPAsyncWebServer-esphome @ 2.1.0
|   |-- AsyncTCP-esphome @ 1.2.2
|-- DNSServer @ 2.0.0
|-- ESPmDNS @ 2.0.0
|-- noise-c @ 0.1.4
|   |-- libsodium @ 1.10018.1
Compiling /data/esp32-front/.pioenvs/esp32-front/src/esphome/components/api/api_connection.cpp.o
Compiling /data/esp32-front/.pioenvs/esp32-front/src/esphome/components/api/api_frame_helper.cpp.o
In file included from src/esphome/components/bluetooth_proxy/bluetooth_proxy.h:9,
                 from src/esphome/components/api/api_connection.cpp:16:
src/esphome/components/esp32_ble_client/ble_client_base.h:77:43: error: 'esphome::esp32_ble_client::espbt::ConnectionType' has not been declared
   virtual void set_connection_type(espbt::ConnectionType ct) { this->connection_type_ = ct; }
                                           ^~~~~~~~~~~~~~
src/esphome/components/esp32_ble_client/ble_client_base.h:89:10: error: 'ConnectionType' in namespace 'esphome::esp32_ble_client::espbt' does not name a type
   espbt::ConnectionType connection_type_{espbt::ConnectionType::V1};
          ^~~~~~~~~~~~~~
src/esphome/components/esp32_ble_client/ble_client_base.h:32:8: error: conflicting return type specified for 'virtual bool esphome::esp32_ble_client::BLEClientBase::gattc_event_handler(esp_gattc_cb_event_t, esp_gatt_if_t, esp_ble_gattc_cb_param_t*)'
   bool gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
        ^~~~~~~~~~~~~~~~~~~
In file included from src/esphome/components/esp32_ble_client/ble_client_base.h:5,
                 from src/esphome/components/bluetooth_proxy/bluetooth_proxy.h:9,
                 from src/esphome/components/api/api_connection.cpp:16:
src/esphome/components/esp32_ble_tracker/esp32_ble_tracker.h:156:16: note: overridden function is 'virtual void esphome::esp32_ble_tracker::ESPBTClient::gattc_event_handler(esp_gattc_cb_event_t, esp_gatt_if_t, esp_ble_gattc_cb_param_t*)'
   virtual void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
                ^~~~~~~~~~~~~~~~~~~
In file included from src/esphome/components/bluetooth_proxy/bluetooth_proxy.h:9,
                 from src/esphome/components/api/api_connection.cpp:16:
src/esphome/components/esp32_ble_client/ble_client_base.h: In member function 'virtual void esphome::esp32_ble_client::BLEClientBase::set_connection_type(int)':
src/esphome/components/esp32_ble_client/ble_client_base.h:77:70: error: 'class esphome::esp32_ble_client::BLEClientBase' has no member named 'connection_type_'; did you mean 'connection_index_'?
   virtual void set_connection_type(espbt::ConnectionType ct) { this->connection_type_ = ct; }
                                                                      ^~~~~~~~~~~~~~~~
                                                                      connection_index_
*** [/data/esp32-front/.pioenvs/esp32-front/src/esphome/components/api/api_connection.cpp.o] Error 1
========================== [FAILED] Took 3.06 seconds ==========================

If I remove the bluetooth_proxy: line, I can then upload the code successfully. If I comment out the Emerald components and sensors, I can also upload the code successfully.

I suspect that there is a conflict between bluetooth proxy and the Emerald component.

Issue connecting

Hi WeekendWarrior1,
I've just tried to upload your code to a ESP32.
The ESP32 can find the Emerald advisor Mac address, however I get an error, and it doesn't seem to connect, and continues scanning.

[23:12:59][C][logger:275]: Logger:
[23:12:59][C][logger:276]: Level: DEBUG
[23:12:59][C][logger:277]: Log Baud Rate: 115200
[23:12:59][C][logger:278]: Hardware UART: UART0
[23:12:59][C][homeassistant.time:010]: Home Assistant Time:
[23:12:59][C][homeassistant.time:011]: Timezone: 'AEST-10AEDT,M10.1.0,M4.1.0/3'
[23:12:59][C][emerald_ble:013]: EMERALD
[23:12:59][C][emerald_ble:014]: Battery 'Emerald Battery'
[23:12:59][C][emerald_ble:014]: Device Class: 'battery'
[23:12:59][C][emerald_ble:014]: State Class: ''
[23:12:59][C][emerald_ble:014]: Unit of Measurement: '%'
[23:12:59][C][emerald_ble:014]: Accuracy Decimals: 0
[23:12:59][C][emerald_ble:015]: Power 'Emerald Power'
[23:12:59][C][emerald_ble:015]: Device Class: 'power'
[23:12:59][C][emerald_ble:015]: State Class: 'measurement'
[23:12:59][C][emerald_ble:015]: Unit of Measurement: 'W'
[23:12:59][C][emerald_ble:015]: Accuracy Decimals: 0
[23:12:59][C][emerald_ble:016]: Daily Energy 'Emerald Daily Energy'
[23:12:59][C][emerald_ble:016]: Device Class: 'energy'
[23:12:59][C][emerald_ble:016]: State Class: 'total_increasing'
[23:12:59][C][emerald_ble:016]: Unit of Measurement: 'kWh'
[23:12:59][C][emerald_ble:016]: Accuracy Decimals: 3
[23:12:59][C][emerald_ble:017]: Total Energy 'Emerald Total Energy'
[23:12:59][C][emerald_ble:017]: Device Class: 'energy'
[23:12:59][C][emerald_ble:017]: State Class: 'total_increasing'
[23:12:59][C][emerald_ble:017]: Unit of Measurement: 'kWh'
[23:12:59][C][emerald_ble:017]: Accuracy Decimals: 3
[23:12:59][D][emerald_ble:018]: pulses_per_kwh_: 3200.000000
[23:12:59][D][emerald_ble:019]: pulse_multiplier_: 9.375000
[23:12:59][C][esp32_ble_tracker:726]: BLE Tracker:
[23:12:59][C][esp32_ble_tracker:727]: Scan Duration: 300 s
[23:12:59][C][esp32_ble_tracker:728]: Scan Interval: 320.0 ms
[23:12:59][C][esp32_ble_tracker:729]: Scan Window: 30.0 ms
[23:12:59][C][esp32_ble_tracker:730]: Scan Type: ACTIVE
[23:12:59][C][ble_client:035]: BLE Client:
[23:12:59][C][ble_client:036]: Address: 30:1b:97:5e:ce:ef
[23:12:59][C][mdns:084]: mDNS:
[23:12:59][C][mdns:085]: Hostname: esp-wifipower
[23:12:59][C][ota:085]: Over-The-Air Updates:
[23:12:59][C][ota:086]: Address: esp-wifipower.local:3232
[23:12:59][C][ota:089]: Using Password.
[23:12:59][C][api:138]: API Server:
[23:12:59][C][api:139]: Address: esp-wifipower.local:6053
[23:12:59][C][api:141]: Using noise encryption: YES
[23:12:59][D][api:102]: Accepted ::FFFF:C0A8:208
[23:13:00][D][api.connection:861]: Home Assistant 2022.7.0 (::FFFF:C0A8:208): Connected successfully
[23:13:00][D][time:042]: Synchronized time: 2022-07-13 23:13:00
[23:13:01][D][esp32_ble_tracker:740]: Found device 55:25:D2:A6:80:DE RSSI=-77
[23:13:01][D][esp32_ble_tracker:761]: Address Type: RANDOM
[23:13:02][D][esp32_ble_tracker:740]: Found device 74:FA:82:EF:C9:22 RSSI=-91
[23:13:02][D][esp32_ble_tracker:761]: Address Type: RANDOM
[23:13:02][D][esp32_ble_tracker:763]: Name: 'SHIELD'
[23:13:02][D][esp32_ble_tracker:765]: TX Power: 2
[23:13:03][D][esp32_ble_tracker:740]: Found device 6D:32:E3:B6:A6:C2 RSSI=-89
[23:13:03][D][esp32_ble_tracker:761]: Address Type: RANDOM
[23:13:03][D][esp32_ble_tracker:765]: TX Power: 2
[23:13:04][D][esp32_ble_tracker:740]: Found device 4F:4E:4E:B4:17:C2 RSSI=-66
[23:13:04][D][esp32_ble_tracker:761]: Address Type: RANDOM
[23:13:47][D][esp32_ble_tracker:740]: Found device 63:D1:28:85:43:86 RSSI=-86
[23:13:47][D][esp32_ble_tracker:761]: Address Type: RANDOM
[23:13:53][D][esp32_ble_tracker:740]: Found device C5:FE:FE:1D:5F:BA RSSI=-90
[23:13:53][D][esp32_ble_tracker:761]: Address Type: RANDOM

This is the MAC address below

[23:14:03][D][ble_client:047]: Found device at MAC address [30:1B:97:5E:CE:EF]
[23:14:03][I][ble_client:085]: Attempting BLE connection to 30:1b:97:5e:ce:ef
[23:14:07]lld_pdu_get_tx_flush_nb HCI packet count mismatch (0, 1)
[23:14:07][W][ble_client:117]: connect to 30:1b:97:5e:ce:ef failed, status=133

Is this something you / others have experienced?

Not getting expected value

Now I am a newbie at this ESP stuff (just got this working 2 days ago.) Fantastic thing don't get me wrong.

Problem for me is that I have 3 Phase system not sure if that really matters but it showing as 500W - 600W on average but having multiple UPS's around the place shows way over that number.

I have checked the following:

  • Paring code
  • Pulses

Just wondering if I am missing something as the results seem off then what I believe what they should be.
Any help would be appreciated.

Thanks!

Pairing codes with leading zero get intepreted as octal

I experienced a small issue connecting to our Emerald EMS because the paring code starts with a zero.

Something in the stack between the YAML input and the generated C++ seems to have interpreted this a an octal literal.
Looking at the generated C++, I saw a different five digit number instead of the correct six digit code.

The workaround I found was to make the pairing_code YAML element a string, then it connects fine.

Perhaps it would be worth updating the sample .yml file to pairing_code: "123123" - might save a bit of bother for ~10% of users:)

Average power conversion

Firstly awesome work @WeekendWarrior1 to get this up and running! Reverse engineering the bluetooth comms protocol is next level.

In setting up my emerald ems, I did notice that the "power" output sensor seems to be off by a factor of 2-5 from the actual power output.

I believe I've tracked down the issue down to the average power equation, and specifically to the conversion between energy [wh] and power [w]

pulse_multiplier_ = (standard_update_interval / (pulses_per_kwh / kw_to_w_conversion));

float avg_watts_within_interval = pulses_within_interval * this->pulse_multiplier_;

In trying to balance the units in the equations I believe we're missing a conversion between "secounds" and "hours". I'll have a stab at an updated formula when I get a chance outside of work.

No Data Coming Out of Arduino Sketch

Hi,

I'm using the latest ESP32 board library (2.0.5) and ino file in this repo to connect to an Emerald EMS and it never receives any data. Here's the serial output from the ESP32:

Starting Arduino BLE Client application...
BLE Advertised Device found: Name: EIAdv [redacted], Address: 30:1b:97:[redacted], serviceUUID: 0000a201-0000-1000-8000-00805f9b34fb
Attempting to connect to device...
Found our device
Forming a connection to 30:1b:97:[redacted]
 - Created client
onConnect
 - Connected to server
We are now connected to the BLE Server.
onAuthenticationComplete
auth_cmpl.success
Pulses: 3200.0000000000000000
Succesfully completed subscribe function

After this point it just sits there indefinitely. I notice that it's never calling onPassKeyRequest, so it doesn't seem to be authenticating with the passcode supplied.

The phone it was paired to has Bluetooth disabled. But the original app still works with the EMS to pull data.

Any ideas on this one?

Teardown Images

Here are the internal images of the Emerald device if you could find some use for it. Btw, thanks for your great work :)

IMG_0571
IMG_0572

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.