diff --git a/get-data.py b/get-inverter-data.py similarity index 93% rename from get-data.py rename to get-inverter-data.py index 279c6d6..7208460 100644 --- a/get-data.py +++ b/get-inverter-data.py @@ -4,7 +4,7 @@ async def get_runtime_data(): #ip_address = '2a00:1028:c000:fdb:730b:1770:8783:6eac' - ip_address = '5.181.93.153' + ip_address = '192.168.2.35' inverter = await goodwe.connect(ip_address) runtime_data = await inverter.read_runtime_data() diff --git a/src/exporter.py b/src/exporter.py index 80d4f0a..be39879 100644 --- a/src/exporter.py +++ b/src/exporter.py @@ -1,5 +1,5 @@ from prometheus_client import CollectorRegistry, Gauge, Counter, Info -from datetime import date, datetime +from datetime import date, datetime, timedelta from decimal import Decimal import prometheus_client as prometheus import xml.etree.ElementTree as ET @@ -13,7 +13,7 @@ #logger = logging.getLogger(__name__) -print("\nGOODWE DATA EXPORTER v1.3.0\n") +print("\nGOODWE DATA EXPORTER v1.4.0\n") QUERY = ''' @@ -41,20 +41,24 @@ def checkArgs(argv): global ENERGY_PRICE global PV_POWER global SCRAPE_SPOT_PRICE + global SPOT_SCRAPE_INTERVAL + global LAST_SPOT_UPDATE # set default values EXPORTER_PORT = 8787 POLLING_INTERVAL = 30 - ENERGY_PRICE = 0 + ENERGY_PRICE = 0.20 PV_POWER = 5670 INVERTER_IP = "" SCRAPE_SPOT_PRICE = False + SPOT_SCRAPE_INTERVAL = 30 + LAST_SPOT_UPDATE = None # help - arg_help = "{0} --port --interval --inverter --energy-price --PVpower [default: False] ".format(argv[0]) + arg_help = "\nREQUIRED PARAMETERS::\n\t-i, --inverter\n\t\tIP adress of the inverter\n\nOPTIONAL PARAMETERS:\n\t-h, --help \n\t\tShows this menu\n\t-p, --port \n\t\texporter port - on which port should the exporter expose data [default:8787]\n\t-t, --interval\n\t\tscrape interval (in seconds) [default:30] \n\t-e. --energy-price \n\t\tprice per KWh in eur [default: 0.20] \n\t-w, --PVpower \n\t\tmaximum KW your PV can produce [default:5670] \n\t-s, --scrape-spot-price \n\t\t[True/False] Set to True, for scraping spot prices from www.ote-cr.cz [default: False] \n\t-x,--spot-scrape-interval \n\t\tscrape interval of spot prices. If you set it too low, ote-cr.cz will block your requests (in minutes) [default:30] ".format(argv[0]) try: - opts, args = getopt.getopt(argv[1:], "hp:t:i:s:", ["help", "port=", "interval=", "inverter=", "energy-price=", "PVpower=", "scrape-spot-price="]) + opts, args = getopt.getopt(argv[1:], "hp:t:i:s:", ["help", "port=", "interval=", "inverter=", "energy-price=", "PVpower=", "scrape-spot-price=", "spot-scrape-interval="]) except: print(arg_help) sys.exit(2) @@ -78,6 +82,11 @@ def checkArgs(argv): SCRAPE_SPOT_PRICE = False else: SCRAPE_SPOT_PRICE = True + elif opt in ("-x", "--spot-scrape-interval"): + # define time for spot price scrape interval + SPOT_SCRAPE_INTERVAL = timedelta(minutes=int(arg)) + # take defined interval so it scrapes it always the 1st time + LAST_SPOT_UPDATE = datetime.now() - SPOT_SCRAPE_INTERVAL # check if Inverter IP is set if not INVERTER_IP: @@ -110,15 +119,17 @@ def parse_spot_data(self, xmlResponse): price_el /= Decimal(1000) #convert MWh -> KWh return price_el - def __init__(self, POLLING_INTERVAL,ENERGY_PRICE,PV_POWER,SCRAPE_SPOT_PRICE): + def __init__(self, POLLING_INTERVAL,ENERGY_PRICE,PV_POWER,SCRAPE_SPOT_PRICE,SPOT_SCRAPE_INTERVAL,LAST_SPOT_UPDATE): self.POLLING_INTERVAL = POLLING_INTERVAL self.ENERGY_PRICE = ENERGY_PRICE self.PV_POWER = PV_POWER self.SCRAPE_SPOT_PRICE = SCRAPE_SPOT_PRICE + self.SPOT_SCRAPE_INTERVAL = SPOT_SCRAPE_INTERVAL + self.LAST_SPOT_UPDATE = LAST_SPOT_UPDATE self.metricsCount = 0 self.g = [] self.i = [] - + # create placeholder for metrics in the register def collector_register(self): async def create_collector_registers(): @@ -153,10 +164,14 @@ def fetch_data(self): # get spot prices if self.SCRAPE_SPOT_PRICE: - query = self.get_query(date.today(), date.today(), in_eur=True) - xmlResponse = asyncio.run(self._download(query)) - self.ENERGY_PRICE = self.parse_spot_data(xmlResponse) - + now = datetime.now() + # if the last spot price update was more that 30min ago, scrape it again + if now - self.LAST_SPOT_UPDATE > self.SPOT_SCRAPE_INTERVAL: + query = self.get_query(date.today(), date.today(), in_eur=True) + xmlResponse = asyncio.run(self._download(query)) + self.ENERGY_PRICE = self.parse_spot_data(xmlResponse) + self.LAST_SPOT_UPDATE = now + async def fetch_inverter(): inverter = await goodwe.connect(INVERTER_IP) runtime_data = await inverter.read_runtime_data() @@ -178,6 +193,7 @@ async def fetch_inverter(): print('-------------------------------------------------------') if self.SCRAPE_SPOT_PRICE: print("energy price(spot):\t\t"+str(self.ENERGY_PRICE)+" eur/KW") + print("last spot price scrape:\t\t"+str(self.LAST_SPOT_UPDATE)) else: print("energy price (fixed):\t\t"+str(self.ENERGY_PRICE)+" eur/KW") print("number of metrics:\t\t"+str(self.metricsCount)) @@ -189,14 +205,21 @@ def main(): print("polling interval:\t\t"+str(POLLING_INTERVAL)+"s") print("inverter scrape IP:\t\t"+str(INVERTER_IP)) - print("fixed energy price: \t\t"+str(ENERGY_PRICE)+" eur/KW") print("total PV power: \t\t"+str(PV_POWER)+"W") + if SCRAPE_SPOT_PRICE: + print("spot price scrape: \t\tEnabled") + print("spot price scrape interval: \t"+str(SPOT_SCRAPE_INTERVAL)+" min") + else: + print("spot price scrape: \t\tDisabled") + print("fixed energy price: \t\t"+str(ENERGY_PRICE)+" eur/KW") inverter_metrics = InverterMetrics( POLLING_INTERVAL=int(POLLING_INTERVAL), ENERGY_PRICE=ENERGY_PRICE, PV_POWER=PV_POWER, - SCRAPE_SPOT_PRICE=SCRAPE_SPOT_PRICE + SCRAPE_SPOT_PRICE=SCRAPE_SPOT_PRICE, + SPOT_SCRAPE_INTERVAL=SPOT_SCRAPE_INTERVAL, + LAST_SPOT_UPDATE=LAST_SPOT_UPDATE ) # Start the server to expose metrics.