Skip to content

Commit

Permalink
Merge pull request #3 from jgyates/master
Browse files Browse the repository at this point in the history
update to jgyates
  • Loading branch information
liltux authored Oct 16, 2018
2 parents e8ca5b5 + f0d6e91 commit 539afa0
Show file tree
Hide file tree
Showing 20 changed files with 1,473 additions and 1,200 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ You can submit your registers from the Monitor page on the web interface.

### Your Environment

- Genereator Model: {Please write here}
- Generator Model: {Please write here}
- Generator Registers: {Please write here}
- Genmon Version: {Please write here}
22 changes: 22 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
# Changelog
All notable changes to this project will be documented in this file. Major releases are documented [here](https://github.com/jgyates/genmon/releases)


## V1.11.8 - 2018-10-16
- Improvements for genmqtt.py to allow for integer and float values to be passed as JSON strings
- Added option for Smart Transfer Switch. This will disable the weekly exercise and remote start in the UI since the transfer switch will handled this.

## V1.11.7 - 2018-10-13
- Add new remote command to reset the current alarm (see Maintenance page)
- Fixed bug in power log for H-100, if you experience problems, reset the power log or delete the file kwlog.txt and restart.
- Moved Update Software in the web interface to the About page
- Moved Submit Registers in the web interface to the About page
- Added Submit Log Files button on the About page
- Added change log to the web interface About page

## V1.11.6 - 2018-10-13
- Changed loading method in genloader.py to work around I/O error with Flask library. As a result the output of the flask library is redirected to /dev/null so it will not be displayed on the console. If you started the software manually from the console and then exited the console and attempted to restart from the web UI (with a settings change) the Flask library used by genserv.py would cause an exception (I/O error). This works around this issue.
- Added more error checking / logging in modbus protocol code. This makes serial over TCP more robust.
- Fixed minor issue in genlog.py
- Improved error logging in myclient.py

## V1.11.5 - 2018-10-12
- Removed restart on I/O error in genserv.

## V1.11.4 - 2018-10-11
- Corrected bug in type in genserv.py. Corrects problem with settings page not displaying.

Expand Down
7 changes: 6 additions & 1 deletion conf/genmqtt.conf
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,16 @@ flush_interval = 0
# to make the path be Home/generator.
root_topic =

# Optional. This value, if true will return numeric values in the Status topic
# as a JSON string which can be converted to an object with integer or float
# values. This applies to items in on the Status page only.
numeric_json = False

# Optional. By default the program will attempt to export all text data that is
# exported by genmon (see the web interface for details). The blacklist
# entry is a way to skip some values that are updated frequently that may not
# be useful in your MQTT based system. For example the modbus packet count
# be suppressed from MQTT by adding "Packet Count" in the line below, or
# "Platform Stats" will exclude all data in the Platform Stats section.
# Multiple entries are separated by commas.
blacklist = Log,System Uptime,Packet Count,Run Time,Monitor Time,Generator Time,External Data
blacklist = Monitor,Log,System Uptime,Packet Count,Run Time,Monitor Time,Generator Time,External Data
38 changes: 29 additions & 9 deletions genloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,6 @@ def InstallLibrary(self, libraryname):
self.LogInfo("Error installing module: " + libraryname + ": "+ str(e1), LogLine = True)
return False
#---------------------------------------------------------------------------
def LogInfo(self, message, LogLine = False):

if not LogLine:
self.LogError(message)
else:
self.LogErrorLine(message)
self.LogConsole(message)
#---------------------------------------------------------------------------
def ValidateConfig(self):

ErrorOccured = False
Expand Down Expand Up @@ -339,7 +331,7 @@ def StartModules(self):
return False
return not ErrorOccured
#---------------------------------------------------------------------------
def LoadModule(self, modulename, args = None):
def LoadModuleAlt(self, modulename, args = None):
try:
self.LogConsole("Starting " + modulename)
# to load as a background process we just use os.system since Popen
Expand All @@ -356,6 +348,34 @@ def LoadModule(self, modulename, args = None):
return False

#---------------------------------------------------------------------------
def LoadModule(self, modulename, args = None):
try:
self.LogConsole("Starting " + modulename)

try:
from subprocess import DEVNULL # py3k
except ImportError:
import os
DEVNULL = open(os.devnull, 'wb')

if not len(args):
args = None

if "genserv.py" in modulename:
OutputStream = DEVNULL
else:
OutputStream = subprocess.PIPE
if args == None:
# close_fds=True
pid = subprocess.Popen([sys.executable, modulename], stdout=OutputStream, stderr=OutputStream, stdin=OutputStream)
else:
pid = subprocess.Popen([sys.executable, modulename, args], stdout=OutputStream, stderr=OutputStream, stdin=OutputStream)
return True

except Exception as e1:
self.LogInfo("Error loading module: " + str(e1), LogLine = True)
return False
#---------------------------------------------------------------------------
def UnloadModule(self, modulename, HardStop = False):
try:
self.LogConsole("Stopping " + modulename)
Expand Down
1 change: 1 addition & 0 deletions genlog.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def LogDataToFile(fileName, time, Event):
address = arg
elif opt in ("-f", "--filename"):
fileName = arg
fileName = fileName.strip()

console.error('Address is ' + address)
console.error('Output file is ' + fileName)
Expand Down
28 changes: 19 additions & 9 deletions genmon.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
print("Error: " + str(e1))
sys.exit(2)

GENMON_VERSION = "V1.11.4"
GENMON_VERSION = "V1.11.8"

#------------ Monitor class ----------------------------------------------------
class Monitor(mysupport.MySupport):
Expand Down Expand Up @@ -437,6 +437,7 @@ def ProcessCommand(self, command, fromsocket = False):
"allregs_json" : [self.Controller.DisplayRegisters, (True, True), True], # display registers
"logs_json" : [self.Controller.DisplayLogs, (True, True), True],
"status_json" : [self.Controller.DisplayStatus, (True,), True],
"status_num_json" : [self.Controller.DisplayStatus, (True,True), True],
"maint_json" : [self.Controller.DisplayMaintenance, (True,), True],
"monitor_json" : [self.DisplayMonitor, (True,), True],
"weather_json" : [self.DisplayWeather, (True,), True],
Expand Down Expand Up @@ -783,8 +784,6 @@ def SocketWorkThread(self, conn):

try:

conn.settimeout(2) # only blok on recv for a small amount of time

statusstr = ""
if self.Controller == None:
outstr = "WARNING: System Initializing"
Expand All @@ -804,12 +803,18 @@ def SocketWorkThread(self, conn):
while True:
try:
data = conn.recv(1024)
if self.Controller == None:
outstr = "Retry, System Initializing"
if len(data):
if self.Controller == None:
outstr = "Retry, System Initializing"
else:
outstr = self.ProcessCommand(data, True)
conn.sendall(outstr.encode())
else:
outstr = self.ProcessCommand(data, True)
conn.sendall(outstr.encode())
# socket closed remotely
break
except socket.timeout:
if self.IsStopping:
break
continue
except socket.error as msg:
try:
Expand All @@ -820,9 +825,14 @@ def SocketWorkThread(self, conn):
break

except socket.error as msg:
self.LogError("Error in SocketWorkThread: " + str(msg))
pass

try:
self.ConnectionList.remove(conn)
conn.close()

except:
pass
# end SocketWorkThread

#---------- interface for heartbeat server thread -------------------------
Expand All @@ -842,7 +852,7 @@ def InterfaceServerThread(self):
while True:
try:
conn, addr = self.ServerSocket.accept()
#self.printToString( 'Connected with ' + addr[0] + ':' + str(addr[1]))
#self.LogError('Connected with ' + addr[0] + ':' + str(addr[1]))
conn.settimeout(0.5)
self.ConnectionList.append(conn)
SocketThread = threading.Thread(target=self.SocketWorkThread, args = (conn,), name = "SocketWorkThread")
Expand Down
2 changes: 2 additions & 0 deletions genmonlib/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,8 @@ def GetPowerHistory(self, CmdString, NoReduce = False):
Items = line.split(",")
if len(Items) != 2:
continue
# remove any kW labels that may be there
Items[1] = self.removeAlpha(Items[1])

if Minutes:
struct_time = time.strptime(Items[0], "%x %X")
Expand Down
53 changes: 28 additions & 25 deletions genmonlib/generac_HPanel.py
Original file line number Diff line number Diff line change
Expand Up @@ -1011,7 +1011,7 @@ def GetStartInfo(self, NoTile = False):
StartInfo["RemoteCommands"] = False
StartInfo["RemoteButtons"] = False
StartInfo["PowerGraph"] = self.PowerMeterIsSupported()
StartInfo["ExerciseControls"] = not self.SmartSwitch
StartInfo["ExerciseControls"] = False # self.SmartSwitch

if not NoTile:
StartInfo["pages"] = {
Expand Down Expand Up @@ -1153,7 +1153,7 @@ def DisplayMaintenance (self, DictOut = False):
return ""

#------------ HPanel::DisplayStatus ----------------------------------------
def DisplayStatus(self, DictOut = False):
def DisplayStatus(self, DictOut = False, JSONNum = False):

try:
Status = collections.OrderedDict()
Expand All @@ -1170,33 +1170,33 @@ def DisplayStatus(self, DictOut = False):
Stat["Time"] = Time


Battery["Battery Voltage"] = self.GetParameter(RegisterEnum.BATTERY_VOLTS, "V", 100.0)
Battery["Battery Charger Current"] = self.GetParameter(RegisterEnum.BATTERY_CHARGE_CURRNT, "A", 10.0)
Battery["Battery Voltage"] = self.ValueOut(self.GetParameter(RegisterEnum.BATTERY_VOLTS, ReturnFloat = True, Divider = 100.0), "V", JSONNum)
Battery["Battery Charger Current"] = self.ValueOut(self.GetParameter(RegisterEnum.BATTERY_CHARGE_CURRNT, ReturnFloat = True, Divider = 10.0), "A", JSONNum)

Engine["Current Status"] = self.GetParameterString(RegisterEnum.STATUS_INFO_START, RegisterEnum.STATUS_INFO_END)
Engine["Previous Status"] = self.GetParameterString(RegisterEnum.STATUS_2_INFO_START, RegisterEnum.STATUS_2_INFO_END)
Engine["Switch State"] = self.GetSwitchState()
Engine["Engine State"] = self.GetEngineState()
Engine["Output Power"] = self.GetPowerOutput()
Engine["Output Power Factor"] = self.GetParameter(RegisterEnum.TOTAL_PF, Divider = 100.0)
Engine["RPM"] = self.GetParameter(RegisterEnum.OUTPUT_RPM)
Engine["Frequency"] = self.GetParameter(RegisterEnum.OUTPUT_FREQUENCY, "Hz", 10.0)
Engine["Throttle Position"] = self.GetParameter(RegisterEnum.THROTTLE_POSITION, "Stp")
Engine["Coolant Temp"] = self.GetParameter(RegisterEnum.COOLANT_TEMP, "F")
Engine["Coolant Level"] = self.GetParameter(RegisterEnum.COOLANT_LEVEL, "Stp")
Engine["Oil Pressure"] = self.GetParameter(RegisterEnum.OIL_PRESSURE, "psi")
Engine["Oil Temp"] = self.GetParameter(RegisterEnum.OIL_TEMP, "F")
Engine["Fuel Level"] = self.GetParameter(RegisterEnum.FUEL_LEVEL)
Engine["Oxygen Sensor"] = self.GetParameter(RegisterEnum.O2_SENSOR)
Engine["Current Phase A"] = self.GetParameter(RegisterEnum.CURRENT_PHASE_A,"A")
Engine["Current Phase B"] = self.GetParameter(RegisterEnum.CURRENT_PHASE_B,"A")
Engine["Current Phase C"] = self.GetParameter(RegisterEnum.CURRENT_PHASE_C,"A")
Engine["Average Current"] = self.GetParameter(RegisterEnum.AVG_CURRENT,"A")
Engine["Voltage A-B"] = self.GetParameter(RegisterEnum.VOLTS_PHASE_A_B,"V")
Engine["Voltage B-C"] = self.GetParameter(RegisterEnum.VOLTS_PHASE_B_C,"V")
Engine["Voltage C-A"] = self.GetParameter(RegisterEnum.VOLTS_PHASE_C_A,"V")
Engine["Average Voltage"] = self.GetParameter(RegisterEnum.AVG_VOLTAGE,"V")
Engine["Air Fuel Duty Cycle"] = self.GetParameter(RegisterEnum.A_F_DUTY_CYCLE, Divider = 10.0)
Engine["Output Power"] = self.ValueOut(self.GetPowerOutput(ReturnFloat = True), "kW", JSONNum)
Engine["Output Power Factor"] = self.ValueOut(self.GetParameter(RegisterEnum.TOTAL_PF, ReturnFloat = True, Divider = 100.0), "", JSONNum)
Engine["RPM"] = self.ValueOut(self.GetParameter(RegisterEnum.OUTPUT_RPM, ReturnInt = True), "", JSONNum)
Engine["Frequency"] = self.ValueOut(self.GetParameter(RegisterEnum.OUTPUT_FREQUENCY, ReturnFloat = True, Divider = 10.0), "Hz", JSONNum)
Engine["Throttle Position"] = self.ValueOut(self.GetParameter(RegisterEnum.THROTTLE_POSITION, ReturnInt = True), "Stp", JSONNum)
Engine["Coolant Temp"] = self.ValueOut(self.GetParameter(RegisterEnum.COOLANT_TEMP, ReturnInt = True), "F", JSONNum)
Engine["Coolant Level"] = self.ValueOut(self.GetParameter(RegisterEnum.COOLANT_LEVEL, ReturnInt = True), "Stp", JSONNum)
Engine["Oil Pressure"] = self.ValueOut(self.GetParameter(RegisterEnum.OIL_PRESSURE, ReturnInt = True), "psi", JSONNum)
Engine["Oil Temp"] = self.ValueOut(self.GetParameter(RegisterEnum.OIL_TEMP, ReturnInt = True), "F", JSONNum)
Engine["Fuel Level"] = self.ValueOut(self.GetParameter(RegisterEnum.FUEL_LEVEL, ReturnInt = True), "", JSONNum)
Engine["Oxygen Sensor"] = self.ValueOut(self.GetParameter(RegisterEnum.O2_SENSOR, ReturnInt = True), "", JSONNum)
Engine["Current Phase A"] = self.ValueOut(self.GetParameter(RegisterEnum.CURRENT_PHASE_A, ReturnInt = True), "A", JSONNum)
Engine["Current Phase B"] = self.ValueOut(self.GetParameter(RegisterEnum.CURRENT_PHASE_B,ReturnInt = True), "A", JSONNum)
Engine["Current Phase C"] = self.ValueOut(self.GetParameter(RegisterEnum.CURRENT_PHASE_C,ReturnInt = True), "A", JSONNum)
Engine["Average Current"] = self.ValueOut(self.GetParameter(RegisterEnum.AVG_CURRENT,ReturnInt = True), "A", JSONNum)
Engine["Voltage A-B"] = self.ValueOut(self.GetParameter(RegisterEnum.VOLTS_PHASE_A_B,ReturnInt = True), "V", JSONNum)
Engine["Voltage B-C"] = self.ValueOut(self.GetParameter(RegisterEnum.VOLTS_PHASE_B_C,ReturnInt = True), "V", JSONNum)
Engine["Voltage C-A"] = self.ValueOut(self.GetParameter(RegisterEnum.VOLTS_PHASE_C_A,ReturnInt = True), "V", JSONNum)
Engine["Average Voltage"] = self.ValueOut(self.GetParameter(RegisterEnum.AVG_VOLTAGE,ReturnInt = True), "V", JSONNum)
Engine["Air Fuel Duty Cycle"] = self.ValueOut(self.GetParameter(RegisterEnum.A_F_DUTY_CYCLE, ReturnFloat = True, Divider = 10.0), "", JSONNum)

if self.SystemInAlarm():
Engine["System In Alarm"] = self.GetAlarmList()
Expand Down Expand Up @@ -1371,7 +1371,10 @@ def PowerMeterIsSupported(self):
# return kW with units i.e. "2.45kW"
def GetPowerOutput(self, ReturnFloat = False):

return self.GetParameter(RegisterEnum.TOTAL_POWER_KW, "kW", ReturnFloat = ReturnFloat)
if ReturnFloat:
return self.GetParameter(RegisterEnum.TOTAL_POWER_KW, ReturnFloat = True)
else:
return self.GetParameter(RegisterEnum.TOTAL_POWER_KW, "kW", ReturnFloat = False)

#---------- HPanel:GetCommStatus -----------------------------------------
# return Dict with communication stats
Expand Down
Loading

0 comments on commit 539afa0

Please sign in to comment.