forked from scadaguru/pysmtreader
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
598 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
MANIFEST | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
.hypothesis/ | ||
.pytest_cache/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
db.sqlite3 | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
||
# Jupyter Notebook | ||
.ipynb_checkpoints | ||
|
||
# pyenv | ||
.python-version | ||
|
||
# celery beat schedule file | ||
celerybeat-schedule | ||
|
||
# SageMath parsed files | ||
*.sage.py | ||
|
||
# Environments | ||
.env | ||
.venv | ||
env/ | ||
venv/ | ||
ENV/ | ||
env.bak/ | ||
venv.bak/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
.spyproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# mkdocs documentation | ||
/site | ||
|
||
# mypy | ||
.mypy_cache/ | ||
|
||
# Ignore for PyCharm | ||
.idea | ||
|
||
# Ignore for erxsyslog | ||
logs/ | ||
|
||
# Ignore config.yaml | ||
config.yaml | ||
settings.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# pysmtreader | ||
|
||
API for https://www.smartmetertexas.com | ||
|
||
# Notes: | ||
1. Make sure to rename config-example.yaml to config.yaml and change "_REPLACE_" text to your values | ||
2. Big thanks to https://github.com/keatontaylor/smartmetertexas-api for providing API documentation |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
logs: | ||
level: debug # debug, info(default), warning, error, critical | ||
log_file_name: pysmt # without extension, log extension will be added automatically | ||
|
||
health_check: | ||
log_info_line_at: 30 # in minutes, 0: disable | ||
|
||
smartmetertexas: # smartmetertexas.com | ||
base_url: https://smartmetertexas.com/api | ||
username: _REPLACE_ # your user name for smartmetertexas.com | ||
password: _REPLACE_ # your password for smartmetertexas.com | ||
esiid: _REPLACE_ # your ESSID for smartmetertexas.com | ||
meter_number: _REPLACE_ # your Meter Number for smartmetertexas.com | ||
poll_interval_minutes: 60 # 0: disable, do set below 30 as smartmetertexas.com will not allow readming more than twice in an hour | ||
wait_interval_before_ondemand_read_minutes: 5 | ||
force_first_read: False # if true it will attempt to read Smart Meter Texas, otherwise at poll_interval | ||
|
||
home_assistant: # Home Assistant access details | ||
base_url: _REPLACE_ # your Home Assistant URL/IP, no slash (/) at the end for example: http://192.168.1.149:8123 | ||
access_token: _REPLACE_ # your Home Assistant access token | ||
ha_entity: sensor.smt_reading # home assistnat entity name to be created |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
version: "3" | ||
services: | ||
pysmtreader: | ||
build: | ||
context: . | ||
dockerfile: ./dockerfile | ||
image: pysmtreader:0.1 | ||
container_name: pysmtreader | ||
volumes: | ||
- ./:/config | ||
- /etc/localtime:/etc/localtime:ro | ||
restart: unless-stopped |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
FROM python:3.8 | ||
|
||
RUN pip3 install requests PyYAML | ||
|
||
COPY ./*.py ./*.yaml /bin/ | ||
WORKDIR /bin | ||
|
||
CMD ["python", "-u", "./main.py"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import datetime | ||
import os | ||
import traceback | ||
import yaml | ||
|
||
|
||
class CommonHelper: | ||
log_level_debug = 1 | ||
log_level_info = 2 | ||
log_level_warning = 3 | ||
log_level_error = 4 | ||
log_level_critical = 5 | ||
|
||
def __init__(self, config_folder): | ||
self.config_folder = config_folder | ||
self.config = yaml.load(open(self.config_folder + 'config.yaml')) | ||
|
||
self.log_level = 2 | ||
if self.config["logs"]["level"] == "debug": | ||
self.log_level = 1 | ||
elif self.config["logs"]["level"] == "info": | ||
self.log_level = 2 | ||
elif self.config["logs"]["level"] == "warning": | ||
self.log_level = 3 | ||
elif self.config["logs"]["level"] == "error": | ||
self.log_level = 4 | ||
elif self.config["logs"]["level"] == "critical": | ||
self.log_level = 5 | ||
|
||
self.log_folder = self.config_folder + "logs/" | ||
self.log_file_name = self.log_folder + \ | ||
self.config["logs"]["log_file_name"] | ||
|
||
if not os.path.exists(self.log_folder): | ||
os.makedirs(self.config_folder + "logs") | ||
self.log_info( | ||
"CommonHelper:__init__(): Creating log folder: " + self.log_folder) | ||
|
||
def get_seconds_till_next_minute(self): | ||
cur_time = datetime.datetime.now() | ||
next_minute = cur_time + \ | ||
datetime.timedelta(seconds=59 - cur_time.second, | ||
microseconds=999999 - cur_time.microsecond) | ||
diff = next_minute - cur_time | ||
diff_ms = (diff.seconds * 1000000 + diff.microseconds) / 1000000.0 | ||
return diff_ms | ||
|
||
def log_debug(self, str_print): | ||
self._log(self.log_level_debug, str_print) | ||
|
||
def log_info(self, str_print): | ||
self._log(self.log_level_info, str_print) | ||
|
||
def log_warning(self, str_print): | ||
self._log(self.log_level_warning, str_print) | ||
|
||
def log_error(self, str_print): | ||
self._log(self.log_level_error, str_print) | ||
|
||
def log_critical(self, str_print): | ||
self._log(self.log_level_critical, str_print) | ||
|
||
def log_data(self, str_print): | ||
self._log(self.log_level_critical, str_print) | ||
|
||
def _log(self, log_level, str_print): | ||
if log_level >= self.log_level: | ||
try: | ||
log_file_name = self.log_file_name + "-" + \ | ||
datetime.datetime.now().strftime('%Y-%m-%d') + ".log" | ||
log_str = datetime.datetime.now().strftime('%H:%M:%S.%f')[ | ||
:-3] + self._get_log_level_to_string(log_level) + str_print | ||
print(log_str) | ||
with open(log_file_name, "a") as log_file: | ||
log_file.write(log_str + "\n") | ||
except Exception as e: | ||
print(datetime.datetime.now().strftime('%H:%M:%S.%f')[ | ||
:-3] + " : CommonHelper:log():Exception: " + str(e)) | ||
|
||
def _get_log_level_to_string(self, log_level): | ||
log_level_str = ": " | ||
if log_level == self.log_level_debug: | ||
log_level_str = ":debug: " | ||
elif log_level == self.log_level_info: | ||
log_level_str = ":info: " | ||
elif log_level == self.log_level_warning: | ||
log_level_str = ":warn: " | ||
elif log_level == self.log_level_error: | ||
log_level_str = ":error: " | ||
elif log_level == self.log_level_critical: | ||
log_level_str = ":critical: " | ||
return log_level_str |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import json | ||
from requests import post, get | ||
import yaml | ||
import traceback | ||
|
||
|
||
class CustomHAHelper: | ||
def __init__(self, config_folder): | ||
try: | ||
self.config = yaml.load(open(config_folder + 'config.yaml')) | ||
self.base_url = self.config["home_assistant"]["base_url"] | ||
self.access_token = self.config["home_assistant"]["access_token"] | ||
except Exception as e: | ||
exception_info = "\nException: {}\n Call Stack: {}".format( | ||
str(e), str(traceback.format_exc())) | ||
print("CustomHAHelper:__init__():Exception: " + exception_info) | ||
|
||
def ha_get_entity_state(self, entity_name): | ||
state = None | ||
response = self.ha_get_sensor(entity_name) | ||
if response: | ||
state = response.json()['state'] | ||
return state | ||
|
||
def ha_get_entity_attribute(self, entity_name, attribute_name): | ||
attribute_value = None | ||
response = self.ha_get_sensor(entity_name) | ||
if response: | ||
attribute_value = response.json()['attributes'][attribute_name] | ||
return attribute_value | ||
|
||
def ha_set_entity_state(self, entity_name, state_str=None, attributes=None, payload=None): | ||
if payload == None: | ||
payload = {"state": state_str} | ||
if attributes: | ||
payload['attributes'] = attributes | ||
return self.ha_update_sensor(entity_name, payload) | ||
|
||
def ha_get_sensor(self, entity_name): | ||
get_url = "{}/api/states/{}".format(self.base_url, entity_name) | ||
headers = { | ||
'Authorization': "Bearer " + self.access_token | ||
} | ||
response = get(get_url, headers=headers) | ||
return response | ||
|
||
def ha_update_sensor(self, entity_name, payload): | ||
post_url = "{}/api/states/{}".format(self.base_url, entity_name) | ||
headers = { | ||
'Authorization': "Bearer " + self.access_token | ||
} | ||
response = post(post_url, data=json.dumps(payload), headers=headers) | ||
return response | ||
|
||
def ha_service_notify(self, message, whom): | ||
post_url = "{}/api/services/notify/{}".format(self.base_url, whom) | ||
headers = { | ||
'Authorization': "Bearer " + self.access_token | ||
} | ||
payload = { | ||
"message": message | ||
} | ||
response = post(post_url, data=json.dumps(payload), headers=headers) | ||
return response | ||
|
||
def ha_service_update_device_tracker(self, mac_address=None, status_str=None, payload=None): | ||
post_url = "{}/api/services/device_tracker/see".format(self.base_url) | ||
headers = { | ||
'Authorization': "Bearer " + self.access_token | ||
} | ||
if payload == None: | ||
payload = { | ||
"mac": mac_address, | ||
"location_name": status_str, | ||
"attributes": {"source_type": "script"} | ||
} | ||
response = post(post_url, data=json.dumps(payload), headers=headers) | ||
return response |
Oops, something went wrong.