APSystem Solar Energy Integration (local)

Hi.

I have APSystems ECU-C and I have been using the integration found at

The thing is that this integration does not provide export/import information that can be very useful to automate optional energy hungry devices like the AC.

So I have created a simple script that scrapes ECU-C local webpage to obtain that info. This script is running in crontab each 5 minutes (ECU-C does not updates the info more often that that) and creates a file in a private network web server. Then, I have sensors in Home Assistant that retrieves that file to populate my dashboard.

It is my first Python script and very beginner with HA so everything is very rudimentary. I am sure you can provide me ideas to improve it. :grin:

Scrapper (/home/apsystems_ecu_scrapper.py):

#coding=utf-8

import urllib2
import json
from argparse import Namespace

#Set ECU-C IP

ECU_IP = "192.168.1.25"

#Get the Power Graph webpage from ECU-C

resp = urllib2.urlopen("http://" + ECU_IP + "/index.php/meter/meter_power_graph")
page = resp.read()

#Original ECU-C page
#print (page)

#Extracts the javascript that contains the graph data
initialPosition = page.find("$('#myChart').highcharts(")
initialPosition = initialPosition + 25
endPosition = page.find(");", initialPosition)

#Extracted javascript data

data = page[initialPosition:endPosition]
#print (data)

#Cleans the data removing all invalid stuff for a JSON object

data = data.replace("//副标题设置", "")
data = data.replace("右侧说明", "")
data = data.replace("subtitle", "'subtitle'")
data = data.replace("text: '',", "'text': ''")
data = data.replace("legend", "'legend'")
data = data.replace("layout", "'layout'")
data = data.replace("align", "'align'")
data = data.replace("verticalAlign", "'verticalAlign'")
data = data.replace("borderWidth", "'borderWidth'")
data = data.replace("series", "'series'")
data = data.replace("name", "'name'")
data = data.replace("// Production A", "")
data = data.replace("//Production CT 1A", "")
data = data.replace("// Production B", "")
data = data.replace("//Production CT 1B", "")
data = data.replace("//Production CT 1C", "")
data = data.replace("// Consumption A", "")
data = data.replace("+ Consumption CT 2A", "")
data = data.replace("// Consumption B", "")
data = data.replace("//Production CT 1B + Consumption CT 2B", "")
data = data.replace("+ Consumption CT 2B", "")
data = data.replace("// Consumption C", "")
data = data.replace("+ Consumption CT 2C", "")
data = data.replace("// Imported/Exported  A", "")
data = data.replace("//Consumption CT 2A", "")
data = data.replace("// Imported/Exported  B", "")
data = data.replace("//Consumption CT 2B", "")
data = data.replace("// Imported/Exported  C", "")
data = data.replace("//Consumption CT 2C", "")

#Converts data arrays to strings
#data = data.replace("data: ", "'data': '")
#data = data.replace(",]", "]'")

#OR fix data arrays format as pure numbers arrays
data = data.replace("data: ", "'data': ")
data = data.replace(",]", "]")

#Changes all ' for "
data = data.replace("'", "\"")

#Fixes latest , because the json is malformed
lastCommaPosition = data.rfind(",")
data = data[:lastCommaPosition] + data[lastCommaPosition + 1:]

#Final data json that has valid format
#print (data)

jsonObject = json.loads(data, object_hook=lambda d: Namespace(**d))

#Get Produced values
producedDataValues = jsonObject.series[0].data

#Get Consumed values
consumedDataValues = jsonObject.series[3].data

#Get Exported values
exportedDataValues = jsonObject.series[6].data

#Get latest position for most recent value
latestProducedDataValue = producedDataValues[len(producedDataValues)-1]
latestConsumedDataValue = consumedDataValues[len(consumedDataValues)-1]
latestExportedDataValue = exportedDataValues[len(exportedDataValues)-1]

#Generate JSON
print "{"
print ' "produced": "' + str(latestProducedDataValue[1]) + '",'
print ' "consumed": "' + str(latestConsumedDataValue[1]) + '",'
print ' "exported": "' + str(latestExportedDataValue[1]) + '"'
print "}"

Shell script to generate the file (/usr/bin/generatePower.sh)

#!/bin/sh
python /home/apsystems_ecu_scrapper.py > /var/www/html/power.txt

Crontab entry:

0,5,10,15,20,25,30,35,40,45,50,55  * * * * generatePower.sh

Home Assistant Sensors (configuration.yaml) (192.168.1.200 is my private web server IP):

rest:    
  - resource: http://192.168.1.200/power.txt
    verify_ssl: false
    sensor:
        - name: Electricidad exportada
          value_template: "{{ value_json.exported }}"
        - name: Electricidad generada
          value_template: "{{ value_json.produced }}"
        - name: Electricidad consumida
          value_template: "{{ value_json.consumed }}"

Example in Dashboard:

Captura de pantalla 2023-06-28 a las 9.15.02

Maybe you find it useful.

Regards.

2 Likes

Hola

Conseguiste que te funcione bien la ECU c en home assistant?

Cualquier ayuda que me pudieras dar te lo agradecería muchísimo

Un saludo

Hola.

La integración que tengo es la que comento y funciona correctamente. ¿Qué necesitas?

Saludos.

1 Like

Soy novato total en home assistant y no se por donde empezar mi objetivo es poder ver lo que está produciendo cada uno de mis 8 paneles solares

I have reformated first post to allow easy copy&paste.

For the people that want to use this device with the CT clamps and use them in the Energy Dashboard, I created this.

2 Likes

Hello
You can find here a yaml file with all sensors to get all energy data from ECU-C.
It works fine without ECU-C interruption

sensor:
    - platform: rest
      name: "PV Power" # Solar production power
      device_class: "power"
      state_class: "measurement"
      unit_of_measurement: "W"
      resource: http://192.168.0.xx/index.php/meter/old_meter_power_graph
      scan_interval: 300
      value_template: >
        {% if value_json is defined %}
            {{ value_json.power1[-1].powerA }}
        {% else %}
            {{ "None" }}
        {% endif %}
      
    - platform: integration
      name: "PV Energy"  # solar production energy
      source: sensor.pv_power
      unit_prefix: "k"
      unit_time: "h"
      method: "left"
      
    - platform: rest
      name: "Import Export Power" # grid import if  + ou export if  -
      device_class: "power"
      state_class: "measurement"
      unit_of_measurement: "W"
      resource: http://192.168.0.xx/index.php/meter/old_meter_power_graph
      scan_interval: 300
      value_template: >
        {% if value_json is defined %}
            {{ value_json.power2[-1].powerA }}
        {% else %}
            {{ "None" }}
        {% endif %}
     
    - platform: template
      sensors:
          export_power: # power grid export
              friendly_name: "Export Power"
              unit_of_measurement: "W"
              device_class: "power"
              value_template: >
                {% set p = states('sensor.import_export_power') | float(0) %}
                {{ ((p | abs) - p) / 2 }}
          import_power:  # power grid import             
              friendly_name: "Import Power"
              unit_of_measurement: "W"
              device_class: "power"
              value_template: >
                {% set p = states('sensor.import_export_power') | float(0) %}
                {{ ((p | abs) + p) / 2 }}

    - platform: integration
      name: "Export Energy" # total grid export energy
      source: sensor.export_power
      unit_prefix: "k"
      unit_time: "h"
      method: "left"

    - platform: integration
      name: "Import Energy" # total grid import energy
      source: sensor.import_power
      unit_prefix: "k"
      unit_time: "h"
      method: "left"

utility_meter: 
    pv_energy_daily: # solar panel daily energy balance
        name: "PV Energy Daily"
        unique_id: pv_energy_daily
        source: sensor.pv_energy
        cycle: daily
    export_energy_daily: # solar production daily export energy
        name: "Export Energy Daily"
        unique_id: export_energy_daily
        source: sensor.export_energy
        cycle: daily
        
    import_energy_daily: # solar production daily import energy
        name: "Import Energy Daily"
        unique_id: import_energy_daily
        source: sensor.export_energy
        cycle: daily

Don’t forget to update your ECU-C IP address in the RES commands.

1 Like

Thank you for your contribution.
Since there is no APSystems integration for the ECU-C, it is impossible to extract data without code.
I wanted to ask you one thing, if it is not a problem:

Would it be possible for you to create a new sensor to control the injection into the grid? This would avoid injecting when the price is negative and it costs money to inject into the grid.

Alternating and direct voltage and current would also be wonderful if they could be obtained.

Thank you very much in advance


Gracias por tu aportación.

Al no haber integración de APSystems para la ECU-C es imposible sacar datos si no es con código.
Quería pedirte si no es un problema una cosa:

¿Sería posible que generes un nuevo sensor para controlar la inyección a red? Así se evitaría inyectar cuando el precio sea negativo y cueste dinero inyectar a red.

El voltaje y corriente de alterna y continua también sería maravilloso si se pudiera conseguir.

Muchas gracias por adelantado

Hi @afternet Are you familiar with the latest version of GitHub - HAEdwin/homeassistant-apsystems_ecu_reader: A Home Assistant custom integration for local querying APsystems ECU's. ?