-
Notifications
You must be signed in to change notification settings - Fork 5
Daily Power Usage / Generation + EG4 Config #3
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
Comments
It's also worth noting that I'm using an EG4 3000EHV-48
|
Hi!
This integration is the first HA-related coding experience for me too. You've done a great job! Thanks for your research and input! I've added the EG4 template, but still trying to figure out, how to include a secret generator in the README to keep it simple and usable. Tried to add a code block generator, but it needs adjustments: https://jsfiddle.net/zw9qjcxh/8/ |
Very nice! That looks like the perfect utility to translate URL's to a usable config. |
Hi all,
Final request: |
Hello 👋 I dipped down the rabbit hole and got it to work. I've used pyscript, installed via HACS, to achieve my result. If you don't want to use pyscript/python, this approach might not work for you.
import time
import hashlib
import requests
@time_trigger("startup")
def init_dessmonitor():
update_auth()
update_inverter()
# Auth every hour
@time_trigger("cron(0 * * * *)")
def update_auth():
if not pyscript.app_config:
log.error("[DessMonitor] Keine App-Konfiguration in pyscript.app_config gefunden!")
return
config = pyscript.app_config[0]
usr = config.get("usr", "default_user")
pwd = config.get("pwd", "default_pwd")
company_key = config.get("company_key", "default_company_key")
salt = str(int(time.time() * 1000))
pwd_sha1 = hashlib.sha1(pwd.encode("utf-8")).hexdigest()
action = "&action=authSource&usr={}&source=1&company-key={}".format(usr, company_key)
sign_str = salt + pwd_sha1 + action
sign = hashlib.sha1(sign_str.encode("utf-8")).hexdigest()
url = f"https://web.dessmonitor.com/public/?sign={sign}&salt={salt}{action}"
log.info(f"[DessMonitor] Auth URL: {url}")
try:
response = task.executor(
requests.get,
url,
timeout=10,
headers={"User-Agent": "Mozilla/5.0 (HomeAssistant pyscript)"},
verify=False
)
if response is None:
raise Exception("task.executor returned None.")
response.raise_for_status()
data = response.json().get("dat", {})
token = data.get("token", "")
secret_value = data.get("secret", "")
if token and secret_value:
state.set("sensor.dessmonitor_token", token)
state.set("sensor.dessmonitor_secret", secret_value)
log.info("[DessMonitor] Auth erfolgreich – Token und Secret aktualisiert")
else:
log.error("[DessMonitor] Auth-Antwort enthält nicht die erwarteten Daten")
except Exception as e:
log.error(f"[DessMonitor] Fehler bei der Auth-Anfrage: {e}")
# Refresh data every minute
@time_trigger("cron(* * * * *)")
def update_inverter():
token = state.get("sensor.dessmonitor_token")
secret_value = state.get("sensor.dessmonitor_secret")
if not token or not secret_value:
log.error("[DessMonitor] Token oder Secret nicht verfügbar – überspringe update_inverter")
return
salt = str(int(time.time() * 1000))
action = ("&action=querySPDeviceLastData&source=1&devcode=6416"
"&pn=YOURPNHERE&devaddr=5&sn=YOURSNHERE&i18n=en_US") # Add your PN & SN here
sign_str = salt + secret_value + token + action
sign = hashlib.sha1(sign_str.encode("utf-8")).hexdigest()
url = f"http://api.dessmonitor.com/public/?sign={sign}&salt={salt}&token={token}{action}"
log.info(f"[DessMonitor] Inverter Data URL: {url}")
try:
response = task.executor(
requests.get,
url,
timeout=10,
headers={"User-Agent": "Mozilla/5.0 (HomeAssistant pyscript)"},
verify=False
)
if response is None:
raise Exception("task.executor returned None.")
response.raise_for_status()
data = response.json()
inverter_attrs = data.get("dat", {}).get("pars", {})
state.set("sensor.inverter_data", "OK", inverter_attrs)
log.info("[DessMonitor] Inverter Daten aktualisiert")
except Exception as e:
log.error(f"[DessMonitor] Fehler bei der Inverter-Daten-Anfrage: {e}")
pyscript:
allow_all_imports: true
hass_is_global: true
apps:
dessmonitor:
- usr: !secret dessmonitor_usr
pwd: !secret dessmonitor_pwd
company_key: !secret dessmonitor_company_key
dessmonitor_usr: YourUsername
dessmonitor_pwd: YourPassword
dessmonitor_company_key: YourCompanyKey # (obtainable via F12 Developer Tools) It's important for pyscript that the script is in an |
Hello everyone and thank you for your work on this. I'm a retired programmer from years ago, but got this up and running with all your code. I have two questions because I am also using an EG4 3000EHV-48:
Do any of you have the same issue? The battery is connected to the inverter and reporting data to the cloud as the battery charge % is visible on the main page of the SmartESS app and the dessmonitor website. I thought I might have the format of the uri wrong, but I have double checked it against the docs. Here is my redacted dessmonitor_api_uri: There is, however, a different uri that returns a different subset of the data with the battery capacity included: Is it possible my configuration is different from everyone else's, or there is a configuration setting I need to include to get SOC included in the recommended uri output?
I'm not sure if that is an artifact from testing or a prefix set elsewhere in the code, but it means that this example is not purely copy-and-paste for amateurs like me. I just removed the "trailer_" everywhere I found it, and the parameters came in as expected. If this is the wrong place for this discussion, please let me know. I stopped programming before Github existed! Thank you. |
Thank you for this it is most appreciated. I am new at homeassistant, based on your use of the python script where would you define the sensor for the inverter data and how would it be defined? Thanks |
Just wanted to say that I got the auth api working without the use of additional python code. Thank you @DooDesch! There's a weird bug where accessing state attributes from the auth return sensor would cause HA / Spook to throw an undefined SHA5 function exception and would prevent the template from loading. This may still happen with the below code. (Salt can be an arbitrary time or number. It doesn't seem important to use a changing number.)
You'd want to use this for every other API function token / secret
Added to template.yaml:
Added to configuration.yaml:
It is also worth noting - I never got the authSource call when I logged in because I was logging in with the QR code. |
Thanks for this, will you be able to update the setup guide incorporating the above details as I still cannot get it to work in HA. |
thanks guys - you helped make my stupid little script. |
Looks like at last week inverter data from web.dessmonitor.com became unavailable very often. Each 3-5 minute. Does some one have the same issue??? How to solve it? |
Yes, have the same issue. I noticed the site dessmonitor.com has an performance issue now, e.g. when login or refresh the page. |
Just wanted to say thank you for creating this!
I was able to dig into their API's a bit further and I created a way to extract the daily generation / consumption.
It was tricky because their API needs a signature that matches the request + some other stuff.
The code to generate a signature and pull daily data is as follows:
Spook Required for SHA1
dess_param - Query parameter. Other options are: PV_OUTPUT_POWER and LOAD_ACTIVE_POWER
dess_action - The daily query.
dess_salt - The current timestamp, but it looks like it can be any number. It doesn't appear that it needs to change either.
dess_secret - This one is tricky. I'm not actually sure how to decode the one store in cookies. It seems like base64, but it doesn't decode to the string that I have above. I used Chrome devtools to override their JS and print out the secret.
Can be found on line 28065 in their app.js. Search for
, s = g["a"].state.user.secret
dess_token - Your token
dess_pn - Part number?
dess_sn - Serial number?
There's also devcode and devaddr, which I'm unsure what they do, but leaving as they were in the request.
I was able to put the above code in secrets.yaml and use it as the resource template.
Now to actually use the data, I had to take their data intervals, get an average, convert to watt hours then sum up.
Since their intervals aren't exactly 5 minutes, sometimes 5 minutes and change, I had to create a time difference and get a hourly fractional to make 5 minute watt hour measurements.
{% if pow_diff < 0 %}
can be replaced with{% if pow_diff > 0 %}
to count charge.This is my first time writing any substantial code for Home Assistant, so apologies if it's not as nice as it could or should be :p
The end result are a bunch of nice daily readings that can be hooked up to the energy flow card!


I'm not confident enough to submit it as a PR, so I figure I'd leave the code here if you or anyone wants to integrate it a bit better than I did.
The text was updated successfully, but these errors were encountered: