Skip to content

Commit e0410d8

Browse files
committed
Changes
modified: README.md modified: greenbutton.json Added util_format Two utilities avilable sce-tou & pep modified: greenbutton_import.py Moved csv parsing into module utilparse.py All new csv formats will be in that module modified: requirements.txt cleanup of non-used modules new file: utilparse.py Added new tags (day and year) for better dashboards without using complex date queries example, use the tags Saturday & Sunday for just weekend Changed measurement to energy - kwhrs was ambigous for a measurement Changed field 'value' to 'kwr' Added new parsing format for Pepco utility Pepco provides hoursly cost so added that as a field
1 parent fb6b7ae commit e0410d8

File tree

6 files changed

+166
-78
lines changed

6 files changed

+166
-78
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Green button import to Influxdb
66
Parse SCE Green Button download files only for now.
7-
<br>Green button data from utilities is not always the same format so this is tuned to SCE's net metering format. Yes, Even SCE has several formats based on customer plan.
7+
<br>Green button data from utilities is not always the same format , two utilities rae now inlcuded.
88
If someone provides sample data for other green button formats (including SCE non Net Metering) I will incorporate.
99

1010
Looking for contributors for other utility formats, code enhancements, bugs, documentation ....
@@ -15,7 +15,9 @@ If you would like to contribute anything including just identifying enhancements
1515
Features
1616
- [X] Parse SCE NetMetering version of Green Button CSV file - Solar
1717
File is grouped by day by Received (Sent to Utility) or Delivered (from Utiliy)
18-
- [X] Parse SCE non-Netmetering version of Green Button CSV file - Normal Residential Customers without solar
18+
- [X] Provide feature to load different utility formats
19+
- SCE (Southern Cal.) Time of use / Net Metering , Pepco (Maryland)
20+
- [ ] Parse SCE non-Netmetering version of Green Button CSV file - Normal Residential Customers without solar
1921
File is group by day and has Consumed header tag
2022
- [X] Send data to influxdb (v1, non-ssl) - should be on private network and not public accessible due to no SSL
2123
- [X] Grafana dashboard to analyze Energy Delivery and Generation

__pycache__/utilparse.cpython-38.pyc

2.45 KB
Binary file not shown.

greenbutton.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
{
2-
"host": "127.0.0.1",
2+
"util_format": "sce-tou",
3+
"host": "influxdbv1.mydomain.org",
34
"port": 8086,
4-
"user": "admin",
5-
"password": "testadmin",
5+
"user": "test",
6+
"password": "test",
67
"dbname": "energy",
78
"ssl_enable": false,
89
"ssl_verify": false,
9-
"timezone": "America/Los_Angeles",
10+
"influx_ver": "V1",
1011
"batchsize": 10000
1112
}

greenbutton_import.py

Lines changed: 14 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,16 @@
1313
# Input - SCE Green Data (TOU Style)
1414
# Output - Inluxdb mesurements (V1)
1515
#
16+
# utilparse.py must be in same directory as this program
1617

1718
__author__ = 'Garrett Gauthier'
1819
__copyright__ = 'Copyright 2022, Garrett Gauthier'
1920
__author__ = 'Garrett Gauthier'
2021
__copyright__ = 'Copyright 2022, Garrett Gauthier'
2122
__credits__ = ['Garrett Gauthier', 'Others soon?']
2223
__license__ = 'GPL'
23-
__version__ = '1.1'
24-
__versiondate__ = '08/18/2022'
24+
__version__ = '1.5'
25+
__versiondate__ = '12/29/2022'
2526
__maintainer__ = 'gauthig@github'
2627
__github__ = 'https://github.com/gauthig/scegreenbutton'
2728
__email__ = 'garrett-g@outlook.com'
@@ -37,6 +38,7 @@
3738
import argparse
3839
import json
3940
import pytz
41+
from utilparse import parse_data
4042

4143

4244
metricsout = []
@@ -47,70 +49,6 @@ def get_config_value(key, default_value):
4749
return config[key]
4850
return default_value
4951

50-
def parse_data(input_file, verbose):
51-
if verbose:
52-
print('Starting parse_data')
53-
54-
55-
56-
point = []
57-
tag_values = []
58-
rows_generated = 0
59-
rows_delivered = 0
60-
tag = ''
61-
pmult = 0
62-
dt_format = '%Y-%m-%d %H:%M:%S'
63-
infile = open(input_file, mode='r')
64-
csv_reader = csv.reader(infile, delimiter=',')
65-
if verbose:
66-
print('File: ', infile)
67-
68-
for row in csv_reader:
69-
if len(row) > 0:
70-
if 'Received' in row[0]:
71-
tag = 'generated'
72-
elif 'Delivered' in row[0]:
73-
tag = 'delivered'
74-
elif 'Consumption' in row[0]:
75-
tag = 'delivered'
76-
elif 'to' in row[0]:
77-
sce_timestamp = row[0].split('to')
78-
# SCE adds non-ASCII charter before the to field, need to strip
79-
sce_timestamp = [
80-
item.replace('\xa0', '') for item in sce_timestamp
81-
]
82-
dt_local = datetime.strptime(sce_timestamp[0], dt_format)
83-
dt_utc = dt_local.astimezone(pytz.UTC)
84-
dt_utc = dt_utc.strftime("%Y-%m-%d %H:%M:%S")
85-
# use local time instead of UTC as you want customer month
86-
dt_month = dt_local.strftime('%B')
87-
if tag == 'generated':
88-
rows_generated = rows_generated + 1
89-
pmult = -1
90-
elif tag == 'delivered':
91-
rows_delivered = rows_delivered + 1
92-
pmult = 1
93-
94-
point = {
95-
"measurement": "kwhrs",
96-
"tags": {
97-
"type": tag,
98-
"month": dt_month
99-
},
100-
"time": dt_utc,
101-
"fields": {
102-
"value": float(row[1]) * pmult
103-
}
104-
}
105-
106-
107-
if verbose:
108-
print(point)
109-
110-
metricsout.append(point)
111-
112-
return (rows_delivered, rows_generated)
113-
11452

11553
def write_csv():
11654
textout = ''
@@ -173,9 +111,7 @@ def send_data(hostname, port, user, password,
173111

174112
parser = \
175113
argparse.ArgumentParser(description="""Loads Green Button csv file
176-
and send formated results to influxdb.
177-
Used for Net Metering format only (solar)"""
178-
)
114+
and send formated results to influxdb. """ )
179115
parser.add_argument('--version',
180116
help='display version number',
181117
action='store_true')
@@ -216,11 +152,18 @@ def send_data(hostname, port, user, password,
216152
)
217153
args = parser.parse_args()
218154

155+
if config['util_format'] not in ('sce-tou','pep'):
156+
print('\n*** json file error ***')
157+
print('Only valid Utility formats are: sce-tou, pep.')
158+
print('Current json value for util_format is ', config['util_format'])
159+
print('Change util_format or create an enhancement request in github to create a new utility format')
160+
sys.exit()
161+
219162
if args.version:
220163
print('sceinfluxdb.py - version', __version__)
221-
sys.exit()
164+
sys.exit(-1)
222165

223-
(delivered, generated) = parse_data(args.file, args.verbose)
166+
(delivered, generated, metricsout) = parse_data(args.file, args.verbose, config['util_format'], metricsout)
224167

225168
if args.csv:
226169
write_csv()

requirements.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
pytz
22
influxdb
33
argparse
4-
datetime
4+
datetime
5+
6+

utilparse.py

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
2+
#utilparse.py
3+
#module to parse all metrics based on utility format
4+
#Notes
5+
# UNIX timestamp for influxdb converted to UTC - grafana will convert back to local
6+
# tags are using local (input file) time zone
7+
#
8+
# Interval times are end times only, start is assumed in a timebased database
9+
10+
from datetime import datetime
11+
import sys
12+
import csv
13+
import pytz
14+
import re
15+
16+
rows_generated = 0
17+
rows_delivered = 0
18+
19+
pmult = 0
20+
21+
def parse_data(input_file, verbose, util_format, metricsout):
22+
if verbose:
23+
print('Starting parse_data')
24+
25+
infile = open(input_file, mode='r')
26+
csv_reader = csv.reader(infile, delimiter=',')
27+
if verbose:
28+
print('File: ', infile)
29+
30+
if util_format == 'sce-tou':
31+
sce_tou_parse(csv_reader, verbose, metricsout)
32+
elif util_format == 'pep':
33+
pep_parse(csv_reader, verbose, metricsout)
34+
return (rows_delivered, rows_generated, metricsout)
35+
36+
37+
def sce_tou_parse(csv_reader, verbose, metricsout):
38+
global rows_generated
39+
global rows_delivered
40+
point = []
41+
tag_values = []
42+
tag = ''
43+
pmult = 0
44+
45+
for row in csv_reader:
46+
if len(row) > 0:
47+
if 'Received' in row[0]:
48+
tag = 'generated'
49+
elif 'Delivered' in row[0]:
50+
tag = 'delivered'
51+
elif 'Consumption' in row[0]:
52+
tag = 'delivered'
53+
elif 'to' in row[0]:
54+
util_timestamp = row[0].split('to')
55+
# SCE adds non-ASCII charter before the to field, need to strip
56+
util_timestamp = [
57+
item.replace('\xa0', '') for item in util_timestamp
58+
]
59+
dt_local = datetime.strptime(util_timestamp[0], '%Y-%m-%d %H:%M:%S')
60+
dt_utc = dt_local.astimezone(pytz.UTC)
61+
dt_utc = dt_utc.strftime("%Y-%m-%d %H:%M:%S")
62+
# use local time instead of UTC as you want customer month
63+
dt_month = dt_local.strftime('%B')
64+
if tag == 'generated':
65+
rows_generated = rows_generated + 1
66+
pmult = -1
67+
elif tag == 'delivered':
68+
rows_delivered = rows_delivered + 1
69+
pmult = 1
70+
if float(row[1]) != 0 :
71+
point = {
72+
"measurement": "energy",
73+
"tags": {
74+
"type": tag,
75+
"month": dt_local.strftime('%B'),
76+
"day": dt_local.strftime('%A'),
77+
"year": dt_local.strftime('%Y'),
78+
},
79+
"time": dt_utc,
80+
"fields": {
81+
"kwh": float(row[1]) * pmult
82+
}
83+
}
84+
85+
if verbose:
86+
print(point)
87+
88+
metricsout.append(point)
89+
90+
def pep_parse(csv_reader, verbose, metricsout):
91+
global rows_generated
92+
global rows_delivered
93+
point = []
94+
tag_values = []
95+
tag = ''
96+
pmult = 0
97+
98+
for row in csv_reader:
99+
if len(row) > 0:
100+
if 'Electric usage' in row[0]:
101+
if float(row[4]) < 0 :
102+
tag = 'generated'
103+
else :
104+
tag = 'delivered'
105+
106+
util_timestamp = row[1]
107+
util_timestamp = str(util_timestamp) + ' ' + str(row[3]) + str(':00')
108+
dt_local = datetime.strptime(util_timestamp ,"%Y-%m-%d %H:%M:%S")
109+
dt_utc = dt_local.astimezone(pytz.UTC)
110+
dt_utc = dt_utc.strftime("%Y-%m-%d %H:%M:%S")
111+
# use local time instead of UTC as you want customer month
112+
113+
if tag == 'generated':
114+
rows_generated = rows_generated + 1
115+
cost = float(re.sub(r'[^0-9]', '', row[6]))/-100
116+
elif tag == 'delivered':
117+
rows_delivered = rows_delivered + 1
118+
cost = float(re.sub(r'[^0-9]', '', row[6]))/100
119+
120+
point = {
121+
"measurement": "energy",
122+
"tags": {
123+
"type": tag,
124+
"month": dt_local.strftime('%B'),
125+
"day": dt_local.strftime('%A'),
126+
"year": dt_local.strftime('%Y'),
127+
},
128+
"time": dt_utc,
129+
"fields": {
130+
"kwh": float(row[4]),
131+
"cost" : cost
132+
}
133+
}
134+
135+
if verbose:
136+
print(point)
137+
138+
metricsout.append(point)
139+
140+
return ()

0 commit comments

Comments
 (0)