Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move code from init to a separate Class #83

Merged
merged 1 commit into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ optional arguments:
--validate validate config file and exit
--create-passhash CREATE_PASSHASH
create passhash from provided passwordand exit
-v, --version show program's version number and exit
```

## Usage
Expand Down
2 changes: 1 addition & 1 deletion config.sample.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"stationId": 1234567,
"inverterId": "1234567890",
"loggerId": "1234567890",
"debug" : false,
"debug": false,
"mqtt":{
"broker": "1.1.1.1",
"port": 1883,
Expand Down
171 changes: 7 additions & 164 deletions solarman/__init__.py
Original file line number Diff line number Diff line change
@@ -1,166 +1,15 @@
"""
Collect PV data from the SolarmanPV API and send Power+Energy data to MQTT
SolarmanPV - Collect PV data from the SolarmanPV API and send Power+Energy data (W+kWh) to MQTT
"""

import argparse
import json
import logging
import sys
import time

from .api import SolarmanApi, ConstructData
from .helpers import ConfigCheck, HashPassword
from .mqtt import Mqtt

logging.basicConfig(level=logging.INFO)

VERSION = "1.0.0"


def load_config(file):
"""
Load configuration
:return:
"""
with open(file, "r", encoding="utf-8") as config_file:
config = json.load(config_file)
return config


def validate_config(file):
"""
Validate config file
:param file: Config file
:return:
"""
config = load_config(file)
ConfigCheck(config)


def create_passhash(password):
"""
Create passhash from password
:param password: Password
:return:
"""
pwstring = HashPassword(password)
print(pwstring.hashed)


def single_run(file):
"""
Output current watts and kilowatts
:return:
"""
config = load_config(file)
pvdata = SolarmanApi(config)

station_data = pvdata.station_realtime
inverter_data = pvdata.device_current_data_inverter
logger_data = pvdata.device_current_data_logger

inverter_data_list = ConstructData(inverter_data).device_current_data
logger_data_list = ConstructData(logger_data).device_current_data

if config.get("debug", False):
logging.info(json.dumps("STATION DATA"))
logging.info(json.dumps(station_data, indent=4, sort_keys=True))
logging.info(json.dumps("INVERTER DATA"))
logging.info(json.dumps(inverter_data, indent=4, sort_keys=True))
logging.info(json.dumps("INVERTER DATA LIST"))
logging.info(json.dumps(inverter_data_list, indent=4, sort_keys=True))
logging.info(json.dumps("LOGGER DATA"))
logging.info(json.dumps(logger_data, indent=4, sort_keys=True))
logging.info(json.dumps("LOGGER DATA LIST"))
logging.info(json.dumps(logger_data_list, indent=4, sort_keys=True))

discard = ["code", "msg", "requestId", "success"]
topic = config["mqtt"]["topic"]

_t = time.strftime("%Y-%m-%d %H:%M:%S")
try:
inverter_device_state = inverter_data["deviceState"]
except KeyError:
inverter_device_state = 128

mqtt_connection = Mqtt(config["mqtt"])

if inverter_device_state == 1:
logging.info(
"%s - Inverter DeviceState: %s -> Publishing to MQTT ...",
_t,
inverter_device_state,
)
for i in station_data:
if station_data[i] and i not in discard:
mqtt_connection.message(topic + "/station/" + i, station_data[i])

for i in inverter_data:
if inverter_data[i] and i not in discard:
mqtt_connection.message(topic + "/inverter/" + i, inverter_data[i])

mqtt_connection.message(
topic + "/inverter/attributes",
json.dumps(inverter_data_list),
)

for i in logger_data:
if logger_data[i] and i not in discard:
mqtt_connection.message(topic + "/logger/" + i, logger_data[i])

mqtt_connection.message(
topic + "/logger/attributes",
json.dumps(logger_data_list),
)

elif inverter_device_state == 128:
logging.info(
"%s - Inverter DeviceState: %s"
"-> No valid inverter status data available",
_t,
inverter_device_state,
)
else:
mqtt_connection.message(
topic + "/inverter/deviceState",
inverter_data["deviceState"],
)
mqtt_connection.message(
topic + "/logger/deviceState", logger_data["deviceState"]
)
logging.info(
"%s - Inverter DeviceState: %s"
"-> Only status MQTT publish (probably offline due to nighttime shutdown)",
_t,
inverter_device_state,
)


def daemon(file, interval):
"""
Run as a daemon process
:param file: Config file
:param interval: Run interval in seconds
:return:
"""
interval = int(interval)
logging.info("Starting daemonized with a %s seconds run interval", str(interval))
while True:
try:
single_run(file)
time.sleep(interval)
except Exception as error: # pylint: disable=broad-except
logging.error("Error on start: %s", str(error))
sys.exit(1)
except KeyboardInterrupt:
logging.info("Exiting on keyboard interrupt")
sys.exit(0)

from .solarmanpv import SolarmanPV

def main():
"""
Main
:return:
"""
parser = argparse.ArgumentParser(
description="Collect data from Trannergy / Solarman API"
Expand Down Expand Up @@ -189,25 +38,19 @@ def main():
default="",
help="create passhash from provided password string and exit",
)
parser.add_argument(
"-v",
"--version",
action="version",
version="solarman-mqtt (%(prog)s) " + VERSION,
)

args = parser.parse_args()
solarman = SolarmanPV(args.file)
if args.single:
single_run(args.file)
solarman.single_run(args.file)
elif args.daemon:
daemon(args.file, args.interval)
solarman.daemon(args.file, args.interval)
elif args.validate:
validate_config(args.file)
solarman.validate_config(args.file)
elif args.create_passhash:
create_passhash(args.create_passhash)
solarman.create_passhash(args.create_passhash)
else:
parser.print_help(sys.stderr)


if __name__ == "__main__":
main()
164 changes: 164 additions & 0 deletions solarman/solarmanpv.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
"""
SolarmanPV - Collect PV data from the SolarmanPV API and send Power+Energy data (W+kWh) to MQTT
"""

import json
import logging
import sys
import time

from .api import SolarmanApi, ConstructData
from .helpers import ConfigCheck, HashPassword
from .mqtt import Mqtt

logging.basicConfig(level=logging.INFO)

class SolarmanPV:
"""
SolarmanPV data collection and MQTT publishing
"""

def __init__(self, file):
self.config = self.load_config(file)
self.api = SolarmanApi(self.config)
self.mqtt = Mqtt(self.config["mqtt"])


def load_config(self, file):
"""
Load configuration
:return:
"""
with open(file, "r", encoding="utf-8") as config_file:
config = json.load(config_file)
return config


def validate_config(self, file):
"""
Validate config file
:param file: Config file
:return:
"""
config = self.load_config(file)
ConfigCheck(config)


def single_run(self, file):
"""
Output current watts and kilowatts
:return:
"""
config = self.load_config(file)
pvdata = SolarmanApi(config)

station_data = pvdata.station_realtime
inverter_data = pvdata.device_current_data_inverter
logger_data = pvdata.device_current_data_logger

inverter_data_list = ConstructData(inverter_data).device_current_data
logger_data_list = ConstructData(logger_data).device_current_data

if config.get("debug", False):
logging.info(json.dumps("STATION DATA"))
logging.info(json.dumps(station_data, indent=4, sort_keys=True))
logging.info(json.dumps("INVERTER DATA"))
logging.info(json.dumps(inverter_data, indent=4, sort_keys=True))
logging.info(json.dumps("INVERTER DATA LIST"))
logging.info(json.dumps(inverter_data_list, indent=4, sort_keys=True))
logging.info(json.dumps("LOGGER DATA"))
logging.info(json.dumps(logger_data, indent=4, sort_keys=True))
logging.info(json.dumps("LOGGER DATA LIST"))
logging.info(json.dumps(logger_data_list, indent=4, sort_keys=True))

discard = ["code", "msg", "requestId", "success"]
topic = config["mqtt"]["topic"]

_t = time.strftime("%Y-%m-%d %H:%M:%S")
try:
inverter_device_state = inverter_data["deviceState"]
except KeyError:
inverter_device_state = 128

mqtt_connection = Mqtt(config["mqtt"])

if inverter_device_state == 1:
logging.info(
"%s - Inverter DeviceState: %s -> Publishing to MQTT ...",
_t,
inverter_device_state,
)
for i in station_data:
if station_data[i] and i not in discard:
mqtt_connection.message(topic + "/station/" + i, station_data[i])

for i in inverter_data:
if inverter_data[i] and i not in discard:
mqtt_connection.message(topic + "/inverter/" + i, inverter_data[i])

mqtt_connection.message(
topic + "/inverter/attributes",
json.dumps(inverter_data_list),
)

for i in logger_data:
if logger_data[i] and i not in discard:
mqtt_connection.message(topic + "/logger/" + i, logger_data[i])

mqtt_connection.message(
topic + "/logger/attributes",
json.dumps(logger_data_list),
)

elif inverter_device_state == 128:
logging.info(
"%s - Inverter DeviceState: %s"
"-> No valid inverter status data available",
_t,
inverter_device_state,
)
else:
mqtt_connection.message(
topic + "/inverter/deviceState",
inverter_data["deviceState"],
)
mqtt_connection.message(
topic + "/logger/deviceState", logger_data["deviceState"]
)
logging.info(
"%s - Inverter DeviceState: %s"
"-> Only status MQTT publish (probably offline due to nighttime shutdown)",
_t,
inverter_device_state,
)


def daemon(self, file, interval):
"""
Run as a daemon process
:param file: Config file
:param interval: Run interval in seconds
:return:
"""
interval = int(interval)
logging.info("Starting daemonized with a %s seconds run interval", str(interval))
while True:
try:
SolarmanPV.single_run(self, file)
time.sleep(interval)
except Exception as error: # pylint: disable=broad-except
logging.error("Error on start: %s", str(error))
sys.exit(1)
except KeyboardInterrupt:
logging.info("Exiting on keyboard interrupt")
sys.exit(0)


def create_passhash(self, password):
"""
Create passhash from password
:param password: Password
:return:
"""
pwstring = HashPassword(password)
print(pwstring.hashed)