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

Updates to work with latest Emon CMS version #170

Merged
merged 3 commits into from
Feb 26, 2022
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
13 changes: 7 additions & 6 deletions conf/interfacer_examples/Renogy/Renogy.emonhub.conf
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
### You will need to install pip: sudo apt-get install python-pip
### And you'll need pymodbus installed: pip install -U pymodbus

#Configuration is for Renogy Rover on USB0
[[Renogy]]
Type = EmonHubModbusRenogyInterfacer
[[[init_settings]]]
com_port = /dev/ttyUSB0
com_baud = 9600
toextract = BatteryPercent,Charging_Stage,BatteryTemp_F,SolarVoltage,SolarCurrent,SolarPower
toextract = BatteryPercent,Charging_Stage,BatteryTemp_F,SolarVoltage,SolarCurrent,SolarPower,PowerGenToday
poll_interval = 30 # More fields can be found in datalist.py
[[[runtimesettings]]]
nodeoffset = 28 #make sure this matches with nodename below
pubchannels = ToEmonCMS,
subchannels = ToRenogy,
basetopic = emonhub/

[nodes]

[[28]]
[[28]]
nodename = Renogy
[[[rx]]]
names = BatteryPercent,Charging_Stage,BatteryTemp_F,SolarVoltage,SolarCurrent,SolarPower
names = BatteryPercent,Charging_Stage,BatteryTemp_F,SolarVoltage,SolarCurrent,SolarPower,PowerGenToday
datacode = 0
scales = 1, 1, 1, 0.1,0.01,1,1
units = %, s, s, V, A,W
units = %, s, s, V, A,W,W
117 changes: 59 additions & 58 deletions src/interfacers/EmonHubModbusRenogyInterfacer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import time
import datetime
import Cargo
import sys

try:
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
Expand All @@ -16,37 +17,36 @@

class EmonHubModbusRenogyInterfacer(EmonHubInterfacer):

def __init__(self, name, com_port='/dev/ttyUSB0', com_baud=9600, toextract='', poll_interval=30):
def __init__(self, name, com_port='/dev/ttyUSB0', com_baud=9600, toextract='' , poll_interval=30):
"""Initialize Interfacer
com_port (string): path to COM port
"""

# Initialization
super(EmonHubModbusRenogyInterfacer, self).__init__(name)
self.poll_interval = int(poll_interval)
self.last_read = time.time()

self._modcon = False
if not pymodbus_found:
self._log.error("PYMODBUS NOT PRESENT BUT NEEDED !!")
# open connection
if pymodbus_found:
self._log.info("pymodbus installed")
self._log.debug("EmonHubModbusRenogyInterfacer args: " + com_port + " - " + str(com_baud))

self._con = self._open_modbus(com_port, com_baud)
if self._con:
self._log.info("Modbus client Connected!")
self._log.debug("EmonHubModbusRenogyInterfacer args: " + str(com_port) + " - " + str(com_baud) )
self._con = self._open_modbus(com_port,com_baud)
if self._modcon :
self._log.info("Modbus client Connected!")
else:
self._log.info("Connection to Modbus client failed. Will try again later")
self._log.info("Connection to Modbus client failed. Will try again later")

def close(self):

# Close TCP connection
if self._con is not None:
self._log.debug("Closing USB/Serial port")
self._con.close()
self._con.close()

def _open_modbus(self, com_port, com_baud):
def _open_modbus(self,com_port,com_baud):
""" Open connection to modbus device """
BATTERY_TYPE = {
1: 'open',
Expand All @@ -55,88 +55,89 @@ def _open_modbus(self, com_port, com_baud):
4: 'lithium',
5: 'self-customized'
}

try:
self._log.info("Starting Modbus client . . . ")
c = ModbusClient(method='rtu', port=com_port, baudrate=com_baud, stopbits=1, bytesize=8, parity='N')
if c.connect():
Model = c.read_holding_registers(12, 8, unit=1)
self._log.info("Connected to Renogy Model: " + str(Model.registers[0]))
BatteryType = c.read_holding_registers(57348, 1, unit=1).registers[0]
BatteryCapacity = c.read_holding_registers(57346, 1, unit=1).registers[0]
self._log.info("Battery Type: " + BATTERY_TYPE[BatteryType] + " " + str(BatteryCapacity) + "ah")
self._modcon = True
else:
self._log.debug("Connection failed")
self._modcon = False
except Exception as e:
self._log.error("modbus connection failed" + str(e))
#raise EmonHubInterfacerInitError('Could not open connection to host %s' %modbus_IP)
self._modcon = False
self._log.info("Starting Modbus client on " + com_port + " at " + com_baud)
# Connect to the controller and get values
client = ModbusClient(method = 'rtu', port = com_port, baudrate = int(com_baud), stopbits = 1, bytesize = 8, parity = 'N')
client.connect()

Model = client.read_holding_registers(12, 8, unit=1)
self._log.info("Connected to Renogy Model: " + str(Model.registers[0]))

BatteryType = client.read_holding_registers(57348, 1, unit=1).registers[0]
BatteryCapacity = client.read_holding_registers(57346, 1, unit=1).registers[0]
self._log.info("Battery Type: " + BATTERY_TYPE[BatteryType] + " " + str(BatteryCapacity) + "ah")

self._modcon = True

except Exception as e:
self._log.error("modbus connection failed " + str(e))
self._log.error("Error on line {}".format(sys.exc_info()[-1].tb_lineno))
pass
else:
return c
return client

def read(self):
now = time.time()
if not now - self.last_read > self.poll_interval:
# Wait to read based on poll_interval
return

self.last_read = now

# CHARGING_STATE = {
# 0: 'deactivated',
# 1: 'activated',
# 2: 'mppt',
# 3: 'equalizing',
# 4: 'boost',
# 5: 'floating',
# 6: 'current limiting'
# }

CHARGING_STATE = {
0: 'deactivated',
1: 'activated',
2: 'mppt',
3: 'equalizing',
4: 'boost',
5: 'floating',
6: 'current limiting'
}

""" Read registers from client"""
if pymodbus_found:
time.sleep(float(self._settings["interval"]))
f = []
c = Cargo.new_cargo(rawdata="")

if not self._modcon:
self._con.close()

if not self._modcon :
self.close()
self._log.info("Not connected, retrying connect" + str(self.init_settings))
self._con = self._open_modbus(self.init_settings["modbus_IP"], self.init_settings["modbus_port"])

if self._modcon:
self._con = self._open_modbus(self.init_settings["com_port"], self.init_settings["com_baud"])

if self._modcon :

# read battery registers
BatteryPercent = self._con.read_holding_registers(256, 1, unit=1).registers[0]
#Charging_Stage = CHARGING_STATE[self._con.read_holding_registers(288, 1, unit=1).registers[0]]
Charging_Stage = self._con.read_holding_registers(288, 1, unit=1).registers[0]
self._log.debug("Battery Percent " + str(BatteryPercent) + "%")
self._log.debug("Charging Stage " + str(Charging_Stage))
self._log.debug("Charging Stage " + str(CHARGING_STATE[Charging_Stage]))

Temp_raw = self._con.read_holding_registers(259, 2, unit=1)
temp_value = Temp_raw.registers[0] & 0x0ff
sign = Temp_raw.registers[0] >> 7
BatteryTemp_C = -(temp_value - 128) if sign == 1 else temp_value
BatteryTemp_F = (BatteryTemp_C * 9/5) + 32
self._log.debug("BatteryTemp_C " + str(BatteryTemp_C))
self._log.debug("BatteryTemp_F " + str(BatteryTemp_F))
self._log.debug("BatteryTemp_F " +str(BatteryTemp_F))

# read Solar registers
SolarVoltage = self._con.read_holding_registers(263, 1, unit=1).registers[0]
SolarCurrent = self._con.read_holding_registers(264, 1, unit=1).registers[0]
SolarPower = self._con.read_holding_registers(265, 1, unit=1).registers[0]
self._log.debug("SolarVoltage " + str(SolarVoltage) + "v")
self._log.debug("SolarCurrent " + str(SolarCurrent) + "a")
self._log.debug("SolarPower " + str(SolarPower) + "w")
self._log.debug("SolarPower " + str(SolarPower) + "w")

PowerGenToday = self._con.read_holding_registers(275, 1, unit=1).registers[0]
self._log.debug("PowerGenToday " + str(PowerGenToday) + "kWh")

# Create a Payload object
c = Cargo.new_cargo()

if int(self._settings['nodeoffset']):
c.nodeid = int(self._settings['nodeoffset'])
c.realdata = [BatteryPercent, Charging_Stage, BatteryTemp_F, SolarVoltage, SolarCurrent, SolarPower]
c.realdata = [BatteryPercent, Charging_Stage, BatteryTemp_F, SolarVoltage, SolarCurrent, SolarPower, PowerGenToday]
else:
self._log.error("nodeoffset needed in emonhub configuration, make sure it exists and is a integer ")
self._log.error("nodeoffset needed in emonhub configuration, make sure it exits and is integer ")
pass

self._log.debug("Return from read data: " + str(c.realdata))
return c