HA_AppDaemonZeverSolarSensor/appd_ZeverSolarSensor.py

126 lines
6.1 KiB
Python

#-------------------------------------------------------------------------------
# Name: appd_ZeverSolarSensor.py
#
# Purpose: To get the Zeversolar solar generation from the local website
# and send it to the front end. It does it by sending it as a
# sensor to the front end. This module parses the value returned
# by the URL call and gives us the:
# - Instantaneous generated power in kW
# - Total generated energy for the day in kWH
# You don't have to make any changes to your configuration.yaml file.
# It automatically generates the sensor for the front end.
#
# Note: Modified for AppDaemon 4
#
# Author: Cheong Koo
#
# Created: 09/08/2021
#
# Note that at night, the server is down as there is no power hence need to check
# Below the reading from the URL separated by CR
# 1 1 EAB9618A0399 RSQMMVXNNPJMNWHY M11 17A31-727R+17829-719R 10:58 05/10/2019 0 1 BD500001018A0080 4978 14.52 OK Error
# 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
#
# In your "apps.yaml" file, put the following lines
# zeversolar_sensor:
# module: appd_ZeverSolarSensor
# class: ZeverSolarSensor
#-------------------------------------------------------------------------------
import hassapi as hass
import urllib.request
import datetime
# Check if server is up or down
# https://docs.python.org/3.1/howto/urllib2.html
from urllib.request import Request, urlopen
from urllib.error import URLError
from datetime import datetime
from datetime import timedelta
#-------------------------------------------------------------------------------
# Global constants
# Get the below from Router
#-------------------------------------------------------------------------------
zeverSolarURL = "http://192.168.1.148/home.cgi" # Change this to your ZeverSolar Inverter IP address
datetimeFormat = "%d/%m/%Y %H:%M" # Format for strftime()
generationFormat = "{:.2f}"
refreshInterval = 120 # Time interval to read the URL in seconds
genPowerIndex = 11 # Index into the returned string from the URL
dailyEnergyIndex = 12 # Index into returned string from the URL
#-------------------------------------------------------------------------------
# Class to be called by AppDaemon
# Remember to declare this class and the module in apps.yaml
#-------------------------------------------------------------------------------
class ZeverSolarSensor(hass.Hass):
#---------------------------------------------------------------------
#-- Initialise the module
def initialize(self):
self.log("------------------------------------------------", log="main_log")
self.log("Initiatilize: ZeverSolar Sensor", log="main_log")
#-- Intialise some local variables
self.generatedPower = 0.00 # In kW
self.totalEnergyDaily = 0.00 # In KwH
self.dateOfReading = datetime.now()
#-- Run first time in 5 sec
self.run_in(self.doGetGenAndSendAsSensor, 5)
#-- Then run it every refreshInterval
startTime = datetime.now() + timedelta(seconds=refreshInterval)
self.run_every(self.doGetGenAndSendAsSensor, startTime, refreshInterval)
#---------------------------------------------------------------------
#-- Get generation and send out as sensor
def doGetGenAndSendAsSensor(self, arg):
self.log("----- ZeverSolar sensor callback -----", log="main_log")
#-- Get the generated power & energy
self.requestSolarGeneration(self)
lastUpdated = self.dateOfReading.strftime(datetimeFormat) # Last updated
#-- Output the sensor values
#-- Instantaneous Generated power
stateInfo1 = generationFormat.format(self.generatedPower)
self.set_state("sensor.zeverSolar_generated_power", state=stateInfo1, attributes=\
{"unit_of_measurement": "kW", \
"device_class": "power", \
"icon": "mdi:white-balance-sunny", \
"friendly_name": "Generated Power",
"lastUpdated": lastUpdated
})
#-- Daily energy generated
#- Icons are located at http://materialdesignicons.com/
stateInfo2 = generationFormat.format(self.totalEnergyDaily)
self.set_state("sensor.zeverSolar_daily_energy", state=stateInfo2, attributes=\
{"unit_of_measurement": "kWh", \
"device_class": "power", \
"icon": "mdi:white-balance-sunny", \
"friendly_name": "Daily Generated Energy",
"lastUpdated": lastUpdated
})
#-- Send out a log to the appdaemon console
self.log("Updated: " + lastUpdated + " Gen: " + stateInfo1 + "kW, Daily energy: " + stateInfo2 + "kWh", log="main_log")
#---------------------------------------------------------------------
#-- Gets the reading from the URL. Returns 0 if no generation
def requestSolarGeneration(self, arg):
self.dateOfReading = datetime.now() # Get date & time of reading
req = Request(zeverSolarURL)
try:
response = urlopen(req)
htmlresponse = response.read()
st = htmlresponse.decode()
st = st.split() # Convert the string into a list
#-- Get the string for the Generated Power and Daily Energy
genPower = st[genPowerIndex]
dailyEnergy = st[dailyEnergyIndex]
#-- Convert string into Int and Float
self.generatedPower = float(genPower)/1000 # Its in W eg. 4978. Convert into kW
self.totalEnergyDaily = float(dailyEnergy) # It is already in kWh eg. 14.52
return
except:
self.log("Error in connecting to Zever solar server", log="main_log")
self.generatedPower = 0.00
self.totalEnergyDaily = 0.00
return