Files
test/power3.py
2025-12-06 11:56:02 +00:00

448 lines
16 KiB
Python

import requests
import polyline
import json
import psycopg2
import psycopg2.extensions
from datetime import datetime, timezone
from geojson import Point, Feature, FeatureCollection, dump
import re
import logging
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('power3.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
conn = psycopg2.connect(host='localhost', database='nws', user='nws', password='nws')
cursor = conn.cursor()
proxies = {"http":"http://nws:nws@localhost:9000"}
aepohmeta = "http://outagemap.aepohio.com.s3.amazonaws.com/resources/data/external/interval_generation_data/metadata.json"
aepwvmeta = "http://outagemap.appalachianpower.com.s3.amazonaws.com/resources/data/external/interval_generation_data/metadata.json"
#firstpowerwvmeta = "https://s3.amazonaws.com/outages.sc4.firstenergycorp.com/resources/data/mdwv/interval_generation_data/metadata.json"
aepkymeta = 'http://outagemap.kentuckypower.com.s3.amazonaws.com/resources/data/external/interval_generation_data/metadata.json'
wvfemeta= 'https://kubra.io/stormcenter/api/v1/stormcenters/6c715f0e-bbec-465f-98cc-0b81623744be/views/5ed3ddf1-3a6f-4cfd-8957-eba54b5baaad/currentState?preview=false'
aepwvkubrameta = "https://kubra.io/stormcenter/api/v1/stormcenters/6674f49e-0236-4ed8-a40a-b31747557ab7/views/8cfe790f-59f3-4ce3-a73f-a9642227411f/currentState?preview=false"
aepohkubrameta = 'https://kubra.io/stormcenter/api/v1/stormcenters/9c0735d8-b721-4dce-b80b-558e98ce1083/views/9b2feb80-69f8-4035-925e-f2acbcf1728e/currentState?preview=false'
aepkykubrameta = 'https://kubra.io/stormcenter/api/v1/stormcenters/23dcd38e-2573-4e20-a463-959b11cae011/views/60f31606-5702-4a1e-a74c-08d866b7a6fa/currentState?preview=false'
aepwvbase = "http://outagemap.appalachianpower.com.s3.amazonaws.com/resources/data/external/interval_generation_data/"
aepohbase = "http://outagemap.aepohio.com.s3.amazonaws.com/resources/data/external/interval_generation_data/"
#firstpowerwvbase = "https://s3.amazonaws.com/outages.sc4.firstenergycorp.com/resources/data/mdwv/interval_generation_data/"
aepkybase = 'http://outagemap.kentuckypower.com.s3.amazonaws.com/resources/data/external/interval_generation_data/'
graysoncounty = 'https://outages.graysonrecc.com/data/boundaries.json'
flemingjson = 'https://outage.fme.coop/data/boundaries.json'
#buckeye rec
#https://outage.buckeyerec.coop/maps/OutageWebMap/maps/GWT.rpc
#washington
#https://weci.ebill.coop/woViewer/MapWiseWeb/GWT.rpc
allcountyoutages = []
S = requests.Session()
def fleming():
logger.info("Starting fleming()")
state = 'KY'
company = 'FLEM'
try:
temp = S.get(flemingjson)
temp.raise_for_status()
tempdata = json.loads(temp.text)
for j in tempdata[0]['boundaries']:
outageinfo = j.get('customersOutNow'),j.get('customersServed'),j.get('name'),state,company
allcountyoutages.append(outageinfo)
logger.info(f"Successfully processed {len(tempdata[0]['boundaries'])} boundaries from fleming")
except requests.exceptions.RequestException as e:
logger.error(f"Request failed for fleming: {e}")
except json.JSONDecodeError as e:
logger.error(f"JSON decode error for fleming: {e}")
except Exception as e:
logger.error(f"Unexpected error in fleming: {e}")
def bigsandy():
logger.info("Starting bigsandy()")
state = 'OH'
company = 'BS'
try:
temp = S.get('https://outagemap.bigsandyrecc.com/data/boundaries.json')
temp.raise_for_status()
tempdata = json.loads(temp.text)
for j in tempdata[0]['boundaries']:
outageinfo = j.get('customersOutNow'),j.get('customersServed'),j.get('name'),state,company
allcountyoutages.append(outageinfo)
logger.info(f"Successfully processed {len(tempdata[0]['boundaries'])} boundaries from bigsandy")
except requests.exceptions.RequestException as e:
logger.error(f"Request failed for bigsandy: {e}")
except json.JSONDecodeError as e:
logger.error(f"JSON decode error for bigsandy: {e}")
except Exception as e:
logger.error(f"Unexpected error in bigsandy: {e}")
def southcentralpower():
logger.info("Starting southcentralpower()")
company = 'SCP'
url = 'https://outage.southcentralpower.com/data/boundaries.json'
Sp = requests.Session()
# Sp.proxies.update(proxies)
try:
response = Sp.get(url)
response.raise_for_status()
tempdata = json.loads(response.text)
state = 'OH'
for j in tempdata[0]['boundaries']:
outageinfo = j.get('customersOutNow'),j.get('customersServed'),j.get('name'),state,company
allcountyoutages.append(outageinfo)
logger.info(f"Successfully processed {len(tempdata[0]['boundaries'])} boundaries from southcentralpower")
except requests.exceptions.RequestException as e:
logger.error(f"Request failed for southcentralpower: {e}")
except json.JSONDecodeError as e:
logger.error(f"JSON decode error for southcentralpower: {e}")
except Exception as e:
logger.error(f"Unexpected error in southcentralpower: {e}")
#wv https://kubra.io/data/e2ae0326-9912-436a-9355-eb2687e798b1/public/reports/7929429f-635d-4761-b6c7-78f646cef3c2_report.json
def ku_get_url():
logger.info("Starting ku_get_url()")
try:
url = 'https://stormcenter.lge-ku.com/reports/1d6f7e68-e192-43c1-bfdc-d809333d8e40'
r = requests.get(url)
r.raise_for_status()
x = re.search(r"instanceId: '(.*?)',", r.text)
if not x:
logger.error("Could not find instanceId in ku_get_url")
return None
urlcom = x.group(1)
urlcom = 'https://kubra.io/stormcenter/api/v1/stormcenters/' + urlcom + '/views/a6cee9e4-312b-4b77-9913-2ae371eb860d/currentState?preview=false'
stuff = S.get(urlcom)
stuff.raise_for_status()
jsonstuff = json.loads(stuff.text)
interval_data = jsonstuff.get('data').get('interval_generation_data')
if not interval_data:
logger.error("Could not find interval_generation_data in ku_get_url")
return None
urlcom = 'https://kubra.io/' + interval_data + '/public/reports/1d6f7e68-e192-43c1-bfdc-d809333d8e40_report.json'
logger.info("Successfully generated URL for ku")
return urlcom
except requests.exceptions.RequestException as e:
logger.error(f"Request failed in ku_get_url: {e}")
return None
except json.JSONDecodeError as e:
logger.error(f"JSON decode error in ku_get_url: {e}")
return None
except Exception as e:
logger.error(f"Unexpected error in ku_get_url: {e}")
return None
def county_json(meta,url,jsonname):
logger.info(f"Starting county_json for meta: {meta}")
try:
response = S.get(meta)
response.raise_for_status()
metainfo = json.loads(response.text)
metadir = metainfo['directory']
url = url + metadir + jsonname
outage = S.get(url)
outage.raise_for_status()
logger.info(f"Successfully fetched county JSON from {url}")
return outage
except requests.exceptions.RequestException as e:
logger.error(f"Request failed in county_json: {e}")
return None
except json.JSONDecodeError as e:
logger.error(f"JSON decode error in county_json: {e}")
return None
except KeyError as e:
logger.error(f"Key error in county_json (missing 'directory'): {e}")
return None
except Exception as e:
logger.error(f"Unexpected error in county_json: {e}")
return None
def ku():
ku = []
url = ku_get_url()
data = S.get(url).text
tempdata = json.loads(data)
temp = tempdata['file_data']['areas'][2]['areas'][0]['areas']
temp1 = tempdata['file_data']['areas'][2]['areas'][1]['areas']
temp2 = tempdata['file_data']['areas'][1]['areas'][0]['areas']
for i in temp:
ku.append(i)
for i in temp1:
ku.append(i)
for i in temp2:
ku.append(i)
for o in ku:
outageinfo = o['cust_a']['val'],o['cust_s'],o['name'].capitalize(),o['state'],o['utility']
allcountyoutages.append(outageinfo)
def grayson():
company = 'GRE'
outage = S.get(graysoncounty)
if outage.headers.get('Content-Type').startswith('application/json'):
tempdata = json.loads(outage.text)
state = 'KY'
for j in tempdata[0]['boundaries']:
outageinfo = j.get('customersOutNow'),j.get('customersServed'),j.get('name'),state,company
allcountyoutages.append(outageinfo)
def aep_county_vawv(meta,url,jsonname):
company = 'AEP'
outage = county_json(meta,url,jsonname)
if outage.headers.get('Content-Type').startswith('application/octet-stream'):
tempdata = json.loads(outage.text)
state = 'WV'
for j in tempdata['file_data']['areas'][0]['areas'][2]['areas']:
outageinfo = j.get('cust_a').get('val'), j.get('cust_s'), j.get('area_name'), state, company
allcountyoutages.append(outageinfo)
state = 'VA'
for j in tempdata['file_data']['areas'][0]['areas'][1]['areas']:
outageinfo = j.get('cust_a').get('val'), j.get('cust_s'), j.get('area_name').capitalize(), state, company
allcountyoutages.append(outageinfo)
def aep_county_oh(meta,url,jsonname):
company = 'AEP'
state = 'OH'
outage = county_json(meta,url,jsonname)
tempdata = json.loads(outage.text)
for j in tempdata['file_data']['areas'][0]['areas'][0]['areas']:
outageinfo = j.get('cust_a').get('val'), j.get('cust_s'), j.get('area_name').capitalize(), state, company
allcountyoutages.append(outageinfo)
def aep_county_ky(meta,url,jsonname):
company = 'AEP'
state = 'KY'
outage = county_json(meta,url,jsonname)
tempdata = json.loads(outage.text)
for j in tempdata['file_data']['areas'][0]['areas'][0]['areas']:
outageinfo = j.get('cust_a').get('val'), j.get('cust_s'), j.get('area_name').capitalize(), state, company
allcountyoutages.append(outageinfo)
def firstenergy_county(meta,url,jsonname):
company = 'FE'
state = 'WV'
outage = county_json(meta,url,jsonname)
if outage.headers.get('Content-Type').startswith('application/octet-stream'):
tempdata = json.loads(outage.text)
for j in tempdata['file_data']['areas'][0]['areas'][0]['areas']:
outageinfo = j.get('cust_a').get('val'), j.get('cust_s'), j.get('area_name').capitalize(),state, company
allcountyoutages.append(outageinfo)
def get_kubra_hexes(url):
outage = S.get(url)
if outage.headers.get('Content-Type').startswith('application/json'):
tempdata = json.loads(outage.text)
bothhex = tempdata.get('data').get('cluster_interval_generation_data')
hexes = bothhex.split('/')
return hexes[2],hexes[3]
def kubra_fe(baseurl1,baseurl2,meta):
hex2 = get_kubra_hexes(meta)
url = baseurl1 + hex2[1] + baseurl2
company = 'FE'
state = 'WV'
outage = S.get(url)
if outage.headers.get('Content-Type').startswith('application/json'):
tempdata = json.loads(outage.text)
for j in tempdata['file_data']['areas']:
if j.get('key') == "county":
outageinfo = j.get('cust_a').get('val'), j.get('cust_s'), j.get('name').capitalize(),state,company
allcountyoutages.append(outageinfo)
def kubra_aep(baseurl1,baseurl2,meta,company='AEP'):
hex2 = get_kubra_hexes(meta)
url = baseurl1 + hex2[1] + baseurl2
outage = S.get(url)
if outage.headers.get('Content-Type').startswith('application/json'):
tempdata = json.loads(outage.text)
process_outage_data(tempdata,company)
def process_outage_data(data,company):
"""
Identifies the data structure and loops through the county-level data.
Args:
data (dict): The parsed JSON data as a Python dictionary.
"""
# Navigate to the primary list of areas
primary_areas = data.get("file_data", {}).get("areas", [])
# If the list is empty, there's nothing to process
if not primary_areas:
print("No 'areas' data found.")
return
# --- This is the key logic to handle both formats ---
# Check the key of the first item to determine the format
first_item_key = primary_areas[0].get("key")
if first_item_key == "state":
# Format 1: Loop through each state object
for state_area in primary_areas:
state_name = state_area.get("name", "Unknown State")
# Get the nested list of counties for this state
county_list = state_area.get("areas", [])
for county in county_list:
# We are now at the county level
if county.get("key") == "county":
outageinfo = county.get('cust_a').get('val'), county.get('cust_s'), county.get('name').capitalize(),county.get('state'),company
allcountyoutages.append(outageinfo)
elif first_item_key == "county":
# Format 2: The primary list is already the county list
for county in primary_areas:
# We are now at the county level
if county.get("key") == "county":
outageinfo = county.get('cust_a').get('val'), county.get('cust_s'), county.get('name').capitalize(),county.get('state'),company
allcountyoutages.append(outageinfo)
else:
print("Unknown data format. Could not find 'state' or 'county' key.")
try:
logger.info("Attempting kubra_fe for FE WV")
kubra_fe('https://kubra.io/data/','/public/reports/8c3b0b30-c9e8-4e8f-8b0d-999c568bb085_report.json',wvfemeta)
except Exception as e:
logger.error(f"Error in kubra_fe for FE WV: {e}")
try:
logger.info("Attempting kubra_aep for AEP WV")
kubra_aep('https://kubra.io/data/','/public/reports/7929429f-635d-4761-b6c7-78f646cef3c2_report.json',aepwvkubrameta)
except Exception as e:
logger.error(f"Error in kubra_aep for AEP WV: {e}")
try:
logger.info("Attempting kubra_aep for AEP OH")
kubra_aep('https://kubra.io/data/','/public/reports/1bc6bd19-2315-4548-980a-6df73b93b355_report.json',aepohkubrameta)
except Exception as e:
logger.error(f"Error in kubra_aep for AEP OH: {e}")
try:
logger.info("Attempting kubra_aep for AEP KY")
kubra_aep('https://kubra.io/data/','/public/reports/8c3b0b30-c9e8-4e8f-8b0d-999c568bb085_report.json',aepkykubrameta)
except Exception as e:
logger.error(f"Error in kubra_aep for AEP KY: {e}")
try:
logger.info("Attempting grayson")
grayson()
except Exception as e:
logger.error(f"Error in grayson: {e}")
try:
logger.info("Attempting ku")
ku()
except Exception as e:
logger.error(f"Error in ku: {e}")
try:
logger.info("Attempting southcentralpower")
southcentralpower()
except Exception as e:
logger.error(f"Error in southcentralpower: {e}")
try:
logger.info("Attempting bigsandy")
bigsandy()
except Exception as e:
logger.error(f"Error in bigsandy: {e}")
try:
logger.info("Attempting fleming")
fleming()
except Exception as e:
logger.error(f"Error in fleming: {e}")
current_timestamp = str(datetime.utcnow())
#for i in allcountyoutages:
# sql = 'insert into countyoutages (outages, served, county, state, update, company) values (%s, %s, %s, %s, %s, %s)'
# val = (i[0], i[1], i[2], i[3], current_timestamp, i[4])
# cursor.execute(sql,val)
#conn.commit()
all_values = []
for i in allcountyoutages:
# Make sure the order matches the SQL placeholders
val = (i[0], i[1], i[2], i[3], current_timestamp, i[4])
all_values.append(val)
# 2. Define the SQL statement ONCE
sql = 'INSERT INTO countyoutages (outages, served, county, state, update, company) VALUES (%s, %s, %s, %s, %s, %s)'
# 3. Execute the command ONCE with all the data
if all_values: # Only execute if there's data to insert
try:
cursor.executemany(sql, all_values)
conn.commit() # Commit after successful execution
logger.info(f"Successfully inserted {len(all_values)} records into the database")
except Exception as e:
logger.error(f"Database error during insert: {e}")
conn.rollback() # Rollback in case of error
else:
logger.warning("No data to insert into the database")
cursor.execute('update countyoutages set cwa = county.cwa from county where county.countyname = countyoutages.county and county.state = countyoutages.state and countyoutages.cwa is null')
conn.commit()
#cursor.execute("delete from countyoutages where cwa != 'RLX'")
cursor.execute("delete from countyoutages where cwa is null")
#cursor.execute("delete from countyoutages where update < now () - interval '365 days'")
conn.commit()
#print(allcountyoutages)
cursor.close()
conn.close()