tolwi / hassio-ecoflow-cloud

EcoFlow Cloud Integration for Home Assistant
353 stars 61 forks source link

EcoFlow Smart Plug support? #114

Open svenerbe opened 1 year ago

svenerbe commented 1 year ago

Hello, thanks for this great integration for EcoFlow devices. It is possible to integrate the smart plugs as well?

I think the sensor values can be collect similar to powerstream with this protobuf....

i'm looking for power consumption and as well to control the Smart Plugs On/Off.

mattwells commented 1 year ago

You can use the Matter integration for Home Assistant to control the Ecoflow Smart Plugs. Sadly it doesn't support the power consumption at this time but it is better than nothing. I am considering adding the smart plugs as well but I am hoping the that Matter integration will be there first as it would be a first party solution for Home Assistant rather than a HACS one.

svenerbe commented 1 year ago

Yes, i know about the matter integration - but its coming without power consumption:-( This was why i ask for integration with your solution...

Qualzz commented 1 year ago

Yes, i know about the matter integration - but its coming without power consumption:-( This was why i ask for integration with your solution...

Did you found a workaround ?

svenerbe commented 1 year ago

not so far:-(

DSRocker commented 8 months ago

I'm not able to add smartplug via matter in HomeAssistant

xfirf commented 7 months ago

I would also like this feature as I do not have a matter hub.

xfirf commented 7 months ago

Today I tried to get the data via mqtt, but unfortenatly there is no useful data for smart plugs available. I´ve contacted Ecoflow for support. Maybe they can fix the results for smart plugs via mqtt.

A small "workaround" would be to read the Smart Plug Loads value from the Powerstream entity. Then at least the sum of all smart plugs would be available for the energy dashboard.

svenerbe commented 7 months ago

Today I tried to get the data via mqtt, but unfortenatly there is no useful data for smart plugs available. I´ve contacted Ecoflow for support. Maybe they can fix the results for smart plugs via mqtt.

A small "workaround" would be to read the Smart Plug Loads value from the Powerstream entity. Then at least the sum of all smart plugs would be available for the energy dashboard.

Hi, just a comment. you get the data as well for smart plugs via mqtt but you need the proto3 definition for decoding. i have a workaround implemented in my node-red inst. i have used the code snipes from the iobroker implementation https://forum.iobroker.net/topic/66743/ecoflow-connector-script-zur-dynamischen-leistungsanpassung/128.

In my solution i have just defined a mqtt client in node red - the decode function with java script and result is than send to homeassitant.

"However, this currently serves as a temporary solution; it would be more elegant to incorporate this functionality directly into the EcoFlow adapter."

xfirf commented 7 months ago

Cool. Could you provide your workaround to me? :)

svenerbe commented 7 months ago

I will see - i need to describe first the workaround.....

xfirf commented 7 months ago

@tolwi is there any chance you will add smart plug support? And if so, is there a way I can support you? I found the official http and mqtt documentation for the smart plugs: https://developer-eu.ecoflow.com/us/document/smartPlug

looks like they´ve added this recently.

xfirf commented 7 months ago

This is the data I was able to receive using a powershell-script from a facebook-group:

DeviceName : DeviceSN : HW52ZDH4SFXXXXXX 2_1.freq : 50 2_1.mqttErrTime : 1706096228 2_1.volt : 229 2_1.geneWatt : 813 2_1.selfEmsSwitch : 1 2_1.geneNum : 1 2_2.task10 : @{taskIndex=9; type=0; timeRange=} 2_1.town : 0 2_2.task11 : @{taskIndex=10; type=0; timeRange=} 2_1.otaDlErr : 0 2_1.country : 0 2_1.rtcResetReason : 1 2_1.heartbeatFrequency : 2 2_1.switchSta : True 2_1.runTime : 181035 2_1.brightness : 50 2_1.otaDlTlsErr : 0 2_1.staIpAddr : 900901056 2_1.consNum : 4 2_1.selfMac : 1001588976 2_1.matterFabric : 0 2_1.maxCur : 0 2_1.parentWifiRssi : -61 2_1.meshId : 11126051 2_1.wifiErrTime : 1706095944 2_2.updateTime : 2024-01-25 10:55:50 2_1.current : 281 2_1.warnCode : 0 2_1.errCode : 0 2_1.temp : 32 2_1.parentMac : 2045644995 2_1.resetCount : 12 2_1.stackMinFree : 22 2_1.consWatt : -300 2_1.lanState : 4 2_1.resetReason : 1 2_1.meshLayel : 1 2_1.updateTime : 2024-01-26 05:29:45 2_1.watts : 280 2_1.maxWatts : 2500 2_1.meshEnable : 0 2_2.task2 : @{taskIndex=1; type=0; timeRange=} 2_2.task3 : @{taskIndex=2; type=0; timeRange=} 2_2.task4 : @{taskIndex=3; type=0; timeRange=} 2_2.task5 : @{taskIndex=4; type=0; timeRange=} 2_2.task1 : @{taskIndex=0; type=0; timeRange=} 2_1.mqttErr : 6 2_1.stackFree : 69 2_2.task6 : @{taskIndex=5; type=0; timeRange=} 2_1.wifiErr : 27 2_2.task7 : @{taskIndex=6; type=0; timeRange=} 2_2.task8 : @{taskIndex=7; type=0; timeRange=} 2_2.task9 : @{taskIndex=8; type=0; timeRange=}

svenerbe commented 7 months ago

@tolwi is there any chance you will add smart plug support? And if so, is there a way I can support you? I found the official http and mqtt documentation for the smart plugs: https://developer-eu.ecoflow.com/us/document/smartPlug

looks like they´ve added this recently.

interesting - have you already try this api? you know how i can request ACCESS_KEY and SECRET_KEY

xfirf commented 7 months ago

You can request a developer access here and then generate them by yourself: https://developer-eu.ecoflow.com/us/security I only used some examples from this facebook group: https://www.facebook.com/groups/1405868123482532/permalink/1575518496517493/

xfirf commented 6 months ago

Any chance somebody is able to help out here?

svenerbe commented 6 months ago

Hello @xfirf, the API seems quite promising. Perhaps it's worth considering developing a new custom component to utilize the API instead of the MQTT integration. I've put together a simple workaround for myself using the Pyscript integration, which might also be helpful for you.

This script gathers all your registered EcoFlow devices and creates an entry in HA with their parameters.

To do this, you'll need to install Pyscript: Python scripting integration - https://github.com/custom-components/pyscript

You'll also need the EcoFlow AccessKey and SecretKey, which you can request at https://developer-eu.ecoflow.com/.

In this code, I collect all attributes starting with key.startswith('2_1.') or key.startswith('20_1.') - indicating Powerstream and Smartplugs. After installation you get a new service in HA like 'Pyscript Python scripting: get_ef_device_list_all'

You need just to copy the following code into ha_config/pyscript:

# Example Code to obtain data from API for specific sensors on an EcoFlow device
# Mark Hicks - 01/29/2024
# written by mail@sven-erbe.de - 14/02/2024

# short description
# script collect all reqistered devices from ecoflow api and creates a entity_id sensor.ecoflow_myapi_{device_name}
# prerequest:
# Pyscript: Python scripting integration - https://github.com/custom-components/pyscript
# ecoflow AccessKey and SecretKey - needs to request on https://developer-eu.ecoflow.com/
# please change accesskey and secret in the script

import sys
import json
import requests
import hashlib
import hmac
import random
import time
import binascii
from urllib.parse import urlencode

def hmac_sha256(data, key):
    hashed = hmac.new(key.encode('utf-8'), data.encode('utf-8'), hashlib.sha256).digest()
    sign = binascii.hexlify(hashed).decode('utf-8')
    return sign

def get_map(json_obj, prefix=""):
  def flatten(obj, pre=""):
    result = {}
    if isinstance(obj, dict):
      for k, v in obj.items():
        result.update(flatten(v, f"{pre}.{k}" if pre else k))
    elif isinstance(obj, list):
      for i, item in enumerate(obj):
        result.update(flatten(item, f"{pre}[{i}]"))
    else: result[pre] = obj
    return result
  return flatten(json_obj, prefix)

def get_qstr(params): return '&'.join([f"{key}={params[key]}" for key in sorted(params.keys())])

def get_api(url, key, secret, params=None):
  nonce     = str(random.randint(100000, 999999))
  timestamp = str(int(time.time() * 1000))
  headers   = {'accessKey':key,'nonce':nonce,'timestamp':timestamp}
  sign_str  = (get_qstr(get_map(params)) + '&' if params else '') + get_qstr(headers)
  print(sign_str)
  headers['sign'] = hmac_sha256(sign_str, secret)
  response = task.executor(requests.get, url, headers=headers, json=params)
  if response.status_code == 200: return response.json()
  else: print(f"get_api: {response.text}")

@service
def get_ef_device_list_all(return_response=True):

  url     = 'https://api.ecoflow.com/iot-open/sign/device/list'
  url_details = 'https://api.ecoflow.com/iot-open/sign/device/quota/all'
  quotas  = ["inv.cfgAcEnabled","inv.cfgAcXboost","bms_bmsStatus.hwVersion"]
  #params  = {"cmdSet":32,"id":66,"quotas":quotas}

  # Replace with valid access/secret keys and device SN
  accesskey     = 'Example123'
  secret  = 'Example123'

  payload = get_api(url,accesskey,secret)

  response_data = payload
  devices = response_data['data']

  if 'data' in payload:
    devices = payload['data']

  for device in devices:
        device_sn = device['sn']
        device_name = device['deviceName']
        if device_name:
            device_name_clean = device_name.replace(" ", "").replace("ü", "ue").replace("ö", "oe").replace("ä", "ae")
        else:
            device_name_clean = ""
        device_name = device_name_clean
        if device_name:  # Überprüfen, ob der Gerätenamen nicht leer ist
            sensor_entity_id = f'sensor.ecoflow_myapi_{device_name}'
        else:
            sensor_entity_id = f'sensor.ecoflow_myapi_{device_sn}'
        # get details
        url_string = url_details + '?sn=' + device_sn

        payload_details = get_api(url_string,accesskey,secret,{"sn":device_sn})

        attributes = {'device_name': device_name, 'online': device['online'], 'serialnumber': device_sn}

        if 'data' in payload_details:
            details = payload_details['data']

            for key, value in details.items():
                if key.startswith('2_1.') or key.startswith('20_1.'):
                    attributes[key] = value
        hass.states.async_set(sensor_entity_id, 'State', attributes=attributes)
xfirf commented 6 months ago

Cool thanks a lot for this. I'll try to get it working and give you feedback later. :-)

xfirf commented 6 months ago

@svenerbe This is so cool. Thanks for the script. Screenshot_20240214-230939 Finally I have the consumption splitted by device and when the Powerstream is offline 🥳

I added a template helper with this code after installing the python add-on and the script: {{ (float(state_attr('sensor.ecoflow_myapi_kuehlschrank', '2_1.watts'))) / 10 }}

Division by 10 as ecoflow provides the watts without semicolon for the decimals, for example 25watt consumption will be shown as 250 instead.

svenerbe commented 6 months ago

Hi, great. how you have scheduled the function? via automation? for power consumption you are right - Operating output power: is 0.1 W - you need division by 10.

xfirf commented 6 months ago

yes, I´ve setup an automation restarting the script every minute:

alias: Ecoflow Smart Plugs Update
description: ""
trigger:
  - platform: time_pattern
    minutes: /1
condition: []
action:
  - service: pyscript.get_ef_device_list_all
    data: {}
mode: single
Nick75wien commented 6 months ago

Thanks a lot! I have done all the steps described to install Pyscript and have copied the script. I also can run the service in HA like 'Pyscript Python scripting: get_ef_device_list_all' but I am not sure if the return is correct and how to get the values like in @xfirf 's post.

Could you please help me what the next steps would be ?

grafik

KR Nick

xfirf commented 6 months ago

After the initial setup you have to setup a automation running this script regulary to get updates. Mine is shown above.

Then you need to create helpers to extract the attributes and map them to sensors you can use for other stuff: Einstellungen / Geräte & Dienste / Helfer / Helfer erstellen / Template / Template für einen Sensor erstellen And then copy this into "Zustandstemplate": {{ (float(state_attr('sensor.ecoflow_myapi_kuehlschrank', '2_1.watts'))) / 10 }}

the /10 is needed as ecoflow provides the watts without a comma or dot but multiplied by 10 to provide them without those characters. you have to change the 'kuehlschrank' regarding to the names you chose for your smart plugs.

Nick75wien commented 6 months ago

I have done like described, but something isn't working. how do I know the correct names? how can I check which values are received with the script ?

mapsgolbeck commented 6 months ago

@svenerbe @xfirf Thanks for scripting. It works...now!

@Nick75wien First, check "Einstellungen - System - Protokolle" that will help you to find log/error-info from scripting

Be sure in EcoFlow-App that all device name of ecoflow-components (Powerstream, Delta, Plugs...and other) are also "phyton - like". A hyphen in name was the problem...and the script will stopped!!! "EF-PLug-1" is my bad example, "EF Plug 1" was better ...

Or, you can add a position to the scripting from Sven : search the position device_name_clean = device_name.replace... and add this:
.replace("-","")

device_name_clean = device_name.replace(" ","").replace("ü","ue").replace("ö","oe").replace("ä","ae").replace("-","")

That was my solution to find the plugs as new entities...

Nick75wien commented 5 months ago

Got it - as mentioned it was in the name of the plugs - i had / in it :-)

saschamb1 commented 4 months ago

Hi,

i tried it and get the following message in my log: Exception in line 76: device_name = device['deviceName'] ^ KeyError: 'deviceName'

i modified in the script only AccessKey and SecretKey.

svenerbe commented 4 months ago

see comment above - this is a problem with your device name, there a 2 option: 1. rename your devices in ecoflow app, 2. replace you specific char in the script - you can search in the script for device_name.replace.

saschamb1 commented 4 months ago

Hi,

I renamed all Plugs to english. It didn't worked. Renamed it back to german. Wrote all in small letters. He created only empty entity's without unique ID's

svenerbe commented 4 months ago

maybe you have a unsupported device for the ecoflow api. Looks like there is no attribute in the payload for device_name. you can replace line 76 with the following:

device_name = device.get('deviceName')

or

if 'deviceName' in device:
    # Key exists
    device_name = device['deviceName']
saschamb1 commented 4 months ago

Hi,

thank you very much. :-) Problem solved. It was an unknown device.

Another question: Is there a solution to use it as a switch?

snmrvoge commented 1 week ago

Unfortunately I can't get any further here, I have filed the script under (/homeassistant/pyscript) - the name of the file : (get_ef_device_list_all.py) did Restart etc. But I don't see any SmartPlugs. On developer.ecoflow.com I don't see any devices either, is that correct? Best, René