Skip to content

Commit 417f9ab

Browse files
authored
Version 1.0
1 parent a7b85e4 commit 417f9ab

File tree

5 files changed

+291
-2
lines changed

5 files changed

+291
-2
lines changed

README.md

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,145 @@
1-
# shelly3em
2-
Shell3EM to InfluxDB
1+
# Shelly3EM to InfluxDB
2+
Small utility to read data from Shelly3EM power monitoring device and store it in InfluxDB.
3+
Requires python3 to run.
4+
5+
# Required python modules
6+
```
7+
urllib3
8+
influxdb
9+
urlencode
10+
json
11+
configparser
12+
```
13+
# Configuration
14+
Edit the config.cfg and enter the following data:
15+
```
16+
[Shelly3EM]
17+
IP=X.X.X.X # Shelly3EM IP address
18+
userpass=user:pass # Username and password delimited by colon
19+
20+
[InfluxDB]
21+
influxdb=0 # 0 - disabled, 1 - enabled
22+
influxdb_host=127.0.0.1 # InfluxDB host IP address
23+
influxdb_port=8086 # InfluxDB port number
24+
influxdb_user=grafana # InfluxDB username
25+
influxdb_password= # InfluxDB password
26+
influxdb_dbname= # InfluxDB database name (have to be created manually)
27+
28+
[General]
29+
verbose=1 # Output verbose data
30+
terminal_output=1 # Output values on terminal
31+
lang=en # en/pl - language version (corresponds to params_XX.json file)
32+
```
33+
# Run
34+
```
35+
bash:/python3 shelly3em.py (or ./shelly3em.py)
36+
* Shelly3EM response: **
37+
{
38+
"wifi_sta": {
39+
"connected": true,
40+
"ssid": "Test",
41+
"ip": "192.168.1.1",
42+
"rssi": -67
43+
},
44+
"cloud": {
45+
"enabled": false,
46+
"connected": false
47+
},
48+
"mqtt": {
49+
"connected": false
50+
},
51+
"time": "09:00",
52+
"unixtime": 1651129257,
53+
"serial": 57905,
54+
"has_update": false,
55+
"mac": "C4ABAB1212AB",
56+
"cfg_changed_cnt": 0,
57+
"actions_stats": {
58+
"skipped": 0
59+
},
60+
"relays": [
61+
{
62+
"ison": true,
63+
"has_timer": false,
64+
"timer_started": 0,
65+
"timer_duration": 0,
66+
"timer_remaining": 0,
67+
"overpower": false,
68+
"is_valid": true,
69+
"source": "input"
70+
}
71+
],
72+
"emeters": [
73+
{
74+
"power": 3.22,
75+
"pf": 0.02,
76+
"current": 0.6,
77+
"voltage": 240.23,
78+
"is_valid": true,
79+
"total": 33543.3,
80+
"total_returned": 101878.3
81+
},
82+
{
83+
"power": -28.99,
84+
"pf": -0.22,
85+
"current": 0.56,
86+
"voltage": 239.2,
87+
"is_valid": true,
88+
"total": 34410.8,
89+
"total_returned": 104140.1
90+
},
91+
{
92+
"power": -33.66,
93+
"pf": -0.24,
94+
"current": 0.6,
95+
"voltage": 238.11,
96+
"is_valid": true,
97+
"total": 55933.9,
98+
"total_returned": 90470.4
99+
}
100+
],
101+
"total_power": -59.43,
102+
"fs_mounted": true,
103+
"update": {
104+
"status": "idle",
105+
"has_update": false,
106+
"new_version": "20220324-123835/v1.11.8-3EM-fix-g0014dcb",
107+
"old_version": "20220324-123835/v1.11.8-3EM-fix-g0014dcb"
108+
},
109+
"ram_total": 49440,
110+
"ram_free": 31476,
111+
"fs_size": 233681,
112+
"fs_free": 156875,
113+
"uptime": 2223746
114+
}
115+
Home grid statistics:
116+
Phase 1
117+
Power [W]: -67.62
118+
Current [A]: 0.66
119+
Voltage [V]: 240.9
120+
Power from grid [Wh]: 33544.5
121+
Power returned [Wh]: 101890.0
122+
Phase 2
123+
Power [W]: -103.23
124+
Current [A]: 0.7
125+
Voltage [V]: 241.41
126+
Power from grid [Wh]: 34411.5
127+
Power returned [Wh]: 104166.0
128+
Phase 3
129+
Power [W]: -58.34
130+
Current [A]: 0.78
131+
Voltage [V]: 241.25
132+
Power from grid [Wh]: 55934.9
133+
Power returned [Wh]: 90494.0
134+
Power usage (all phases) [W] : -229.19
135+
Total power from grid [Wh] : 123890.9
136+
Total power returned [Wh] : 296550.0
137+
```
138+
# Known Issues
139+
You tell me :)
140+
141+
# Contrib
142+
Feel free to suggest :)
143+
If You want to rewrite or/add change anything - please fork Your own project.
144+
145+
Enjoy :)

config.cfg

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[Shelly3EM]
2+
IP=X.X.X.X
3+
userpass=user:pass
4+
5+
[InfluxDB]
6+
influxdb=0
7+
influxdb_host=127.0.0.1
8+
influxdb_port=8086
9+
influxdb_user=grafana
10+
influxdb_password=
11+
influxdb_dbname=
12+
13+
[General]
14+
verbose=1
15+
terminal_output=1
16+
lang=en

params_en.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"power": "Power [W]",
3+
"current": "Current [A]",
4+
"voltage": "Voltage [V]",
5+
"total":"Power from grid [Wh]",
6+
"total_returned": "Power returned [Wh]",
7+
"total_power": "Power usage (all phases) [W]",
8+
"total_sum": "Total power from grid [Wh]",
9+
"total_returned_sum": "Total power returned [Wh]"
10+
}

params_pl.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"power": "Moc [W]",
3+
"current": "Prąd [A]",
4+
"voltage": "Napięcie [V]",
5+
"total":"Pobrane z sieci [Wh]",
6+
"total_returned": "Oddane do sieci [Wh]",
7+
"total_power": "Suma mocy 3ech faz [W]",
8+
"total_sum": "Pobrane z sieci w sumie [Wh]",
9+
"total_returned_sum": "Oddane do sieci w sumie [Wh]"
10+
}

shelly3em.py

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#!/usr/bin/python3
2+
#
3+
# Script to get data from Shelly3EM and store it in InfluxDB
4+
#
5+
# Author: Michalux
6+
# Version: 1.0
7+
#
8+
9+
import configparser
10+
import urllib3
11+
from urllib.parse import urlencode
12+
import json
13+
import os.path
14+
import sys
15+
import datetime
16+
from datetime import datetime
17+
from influxdb import InfluxDBClient
18+
19+
# Prepare data to write do InfluxDB
20+
def PrepareInfluxData(IfData, fieldname, fieldvalue):
21+
IfData[0]["fields"][fieldname] = float(fieldvalue)
22+
return IfData
23+
24+
def Write2InfluxDB(IfData):
25+
ifclient.write_points(IfData)
26+
27+
os.chdir(os.path.dirname(os.path.abspath(sys.argv[0])))
28+
29+
# CONFIG
30+
configParser = configparser.RawConfigParser()
31+
configFilePath = r'./config.cfg'
32+
configParser.read(configFilePath)
33+
34+
SHELLYIP=configParser.get('Shelly3EM', 'IP')
35+
SHELLYUSERPASS=configParser.get('Shelly3EM', 'userpass')
36+
INFLUXDB = configParser.get("InfluxDB", "influxdb")
37+
IFHOST = configParser.get("InfluxDB", "influxdb_host")
38+
IFPORT = configParser.get("InfluxDB", "influxdb_port")
39+
IFUSER = configParser.get("InfluxDB", "influxdb_user")
40+
IFPASS = configParser.get("InfluxDB", "influxdb_password")
41+
IFDB = configParser.get("InfluxDB", "influxdb_dbname")
42+
verbose = configParser.get("General", "verbose")
43+
termout = configParser.get("General", "terminal_output")
44+
lang = configParser.get("General", "lang")
45+
46+
# Get parameter's definitions to monitor
47+
pfilename="./params_"+lang+".json"
48+
with open(pfilename) as paramfile:
49+
params=json.loads(paramfile.read())
50+
51+
# Initialise InfluxDB support
52+
if INFLUXDB == "1":
53+
timestamputc = str(datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S"))
54+
ifclient = InfluxDBClient(IFHOST, IFPORT, IFUSER, IFPASS, IFDB)
55+
InfluxData = [{"measurement": "Shelly3EM", "time": timestamputc, "fields": {}}]
56+
57+
# Initialise HTTP Manager
58+
http = urllib3.PoolManager()
59+
header = urllib3._collections.HTTPHeaderDict()
60+
61+
# Get data from Shelly3EM
62+
header = urllib3.make_headers(basic_auth=SHELLYUSERPASS)
63+
URL='http://'+SHELLYIP+'/status'
64+
try:
65+
apiresponse = http.request('GET', URL, headers=header)
66+
except:
67+
print("** Error getting data from Shelly3EM **")
68+
sys.exit(1)
69+
response = json.loads(apiresponse.data)
70+
71+
if verbose=="1":
72+
print("** Shelly3EM response: **")
73+
print(json.dumps(response, indent=4, sort_keys=False, ensure_ascii=False))
74+
75+
# Parse Shelly3EM response
76+
Total=0
77+
TotalR=0
78+
if termout=="1":
79+
print("Home grid statistics:")
80+
faza=1
81+
for shellydata in response["emeters"]:
82+
if termout=="1":
83+
print("Phase "+str(faza))
84+
for param in params:
85+
if param != "total_power" and param != "total_sum" and param != "total_returned_sum":
86+
if termout=="1":
87+
print(" "+params[param]+": "+str(shellydata[param]))
88+
param_name=param+"_"+str(faza)
89+
if param == "total":
90+
Total+=shellydata[param]
91+
if param == "total_returned":
92+
TotalR+=shellydata[param]
93+
if INFLUXDB=="1":
94+
PrepareInfluxData(InfluxData, param_name, shellydata[param])
95+
faza+=1
96+
if termout=="1":
97+
print(params["total_power"]+" : "+str(response["total_power"]))
98+
print(params["total_sum"]+" : "+str(Total))
99+
print(params["total_returned_sum"]+" : "+str(TotalR))
100+
if INFLUXDB=="1":
101+
PrepareInfluxData(InfluxData, "total_power", response["total_power"])
102+
PrepareInfluxData(InfluxData, "total_sum", Total)
103+
PrepareInfluxData(InfluxData, "total_returned_sum", TotalR)
104+
105+
# Write data to Influx Database
106+
if INFLUXDB=="1":
107+
Write2InfluxDB(InfluxData)
108+
if verbose=="1":
109+
print("** Data written to InfluxDB: **")
110+
print(json.dumps(InfluxData, indent=4, sort_keys=False, ensure_ascii=False))

0 commit comments

Comments
 (0)