Skip to content

Commit

Permalink
genmqtt and smart transfer switch updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason Yates authored and Jason Yates committed Oct 16, 2018
1 parent 84214ec commit f0d6e91
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 65 deletions.
5 changes: 5 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# 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.
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
5 changes: 3 additions & 2 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.7"
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 @@ -851,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
46 changes: 23 additions & 23 deletions genmonlib/generac_HPanel.py
Original file line number Diff line number Diff line change
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
41 changes: 22 additions & 19 deletions genmonlib/generac_evolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -2906,13 +2906,16 @@ def GetThresholdVoltage(self, ReturnInt = False):
return self.GetParameter("0011", ReturnInt = ReturnInt, Label = "V")

#------------ Evolution:GetSetOutputVoltage --------------------------------
def GetSetOutputVoltage(self):
def GetSetOutputVoltage(self, ReturnInt = False):

# get set output voltage
if not self.EvolutionController or not self.LiquidCooled:
return ""
if ReturnInt:
return 0
else:
return ""

return self.GetParameter("0237", Label = "V")
return self.GetParameter("0237", Label = "V", ReturnInt = ReturnInt)

#------------ Evolution:GetStartupDelay ------------------------------------
def GetStartupDelay(self):
Expand Down Expand Up @@ -3255,8 +3258,8 @@ def DisplayOutage(self, DictOut = False):
if len(Value):
OutageData["Utility Voltage"] = Value

OutageData["Utility Voltage Minimum"] = "%dV " % (self.UtilityVoltsMin)
OutageData["Utility Voltage Maximum"] = "%dV " % (self.UtilityVoltsMax)
OutageData["Utility Voltage Minimum"] = "%d V " % (self.UtilityVoltsMin)
OutageData["Utility Voltage Maximum"] = "%d V " % (self.UtilityVoltsMax)

OutageData["Utility Threshold Voltage"] = self.GetThresholdVoltage()

Expand All @@ -3274,7 +3277,7 @@ def DisplayOutage(self, DictOut = False):
return Outage

#------------ Evolution:DisplayStatus --------------------------------------
def DisplayStatus(self, DictOut = False, Reg0001Value = None):
def DisplayStatus(self, DictOut = False, JSONNum = False, Reg0001Value = None):

try:
Status = collections.OrderedDict()
Expand All @@ -3299,36 +3302,36 @@ def DisplayStatus(self, DictOut = False, Reg0001Value = None):
if self.SystemInAlarm():
Engine["System In Alarm"] = self.GetAlarmState()

Engine["Battery Voltage"] = self.GetBatteryVoltage()
Engine["Battery Voltage"] = self.ValueOut(self.GetBatteryVoltage(ReturnFloat = True), "V", JSONNum)
if self.EvolutionController and self.LiquidCooled:
Engine["Battery Status"] = self.GetBatteryStatus()

Engine["RPM"] = self.GetRPM()
Engine["RPM"] = self.ValueOut(self.GetRPM(ReturnInt = True), "", JSONNum)

Engine["Frequency"] = self.GetFrequency()
Engine["Output Voltage"] = self.GetVoltageOutput()
Engine["Frequency"] = self.ValueOut(self.GetFrequency(ReturnFloat = True), "Hz", JSONNum)
Engine["Output Voltage"] = self.ValueOut(self.GetVoltageOutput(ReturnInt = True), "V", JSONNum)

if self.PowerMeterIsSupported():
Engine["Output Current"] = self.GetCurrentOutput()
Engine["Output Power (Single Phase)"] = self.GetPowerOutput()
Engine["Output Current"] = self.ValueOut(self.GetCurrentOutput(ReturnFloat = True), "A", JSONNum)
Engine["Output Power (Single Phase)"] = self.ValueOut(self.GetPowerOutput(ReturnFloat = True), "kW", JSONNum)

Engine["Active Rotor Poles (Calculated)"] = self.GetActiveRotorPoles()
Engine["Active Rotor Poles (Calculated)"] = self.ValueOut(self.GetActiveRotorPoles(ReturnInt = True), "", JSONNum)

if self.bDisplayUnknownSensors:
Engine["Unsupported Sensors"] = self.DisplayUnknownSensors()


if self.EvolutionController and self.LiquidCooled:
Line["Transfer Switch State"] = self.GetTransferStatus()
Line["Utility Voltage"] = self.GetUtilityVoltage()
Line["Utility Voltage"] = self.ValueOut(self.GetUtilityVoltage(ReturnInt = True), "V", JSONNum)
#
Line["Utility Voltage Max"] = "%dV " % (self.UtilityVoltsMax)
Line["Utility Voltage Min"] = "%dV " % (self.UtilityVoltsMin)
Line["Utility Threshold Voltage"] = self.GetThresholdVoltage()
Line["Utility Voltage Max"] = self.ValueOut(self.UtilityVoltsMax, "V", JSONNum)
Line["Utility Voltage Min"] = self.ValueOut(self.UtilityVoltsMin, "V", JSONNum)
Line["Utility Threshold Voltage"] = self.ValueOut(self.GetThresholdVoltage(ReturnInt = True), "V", JSONNum)

if self.EvolutionController and self.LiquidCooled:
Line["Utility Pickup Voltage"] = self.GetPickUpVoltage()
Line["Set Output Voltage"] = self.GetSetOutputVoltage()
Line["Utility Pickup Voltage"] = self.ValueOut(self.GetPickUpVoltage(ReturnInt = True), "V", JSONNum)
Line["Set Output Voltage"] = self.ValueOut(self.GetSetOutputVoltage(ReturnInt = True), "V", JSONNum)

# Generator time
Time["Monitor Time"] = datetime.datetime.now().strftime("%A %B %-d, %Y %H:%M:%S")
Expand Down
44 changes: 38 additions & 6 deletions genmonlib/mysupport.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# MODIFICATIONS:
#-------------------------------------------------------------------------------

import os, sys, time, collections, threading, socket
import os, sys, time, collections, threading, socket, json

from genmonlib import mycommon, myplatform, myconfig

Expand Down Expand Up @@ -139,6 +139,38 @@ def WaitForExit(self, Name, timeout = None):

return Thread.Wait(timeout)

#------------ MySupport::ValueOut ------------------------------------------
def ValueOut(self, value, unit, NoString = False):
try:

if NoString:
ReturnDict = collections.OrderedDict()
ReturnDict["unit"] = unit
DefaultReturn = json.dumps({'value': 0}, sort_keys=False)
else:
DefaultReturn = ""
if isinstance(value, int):
if not NoString:
return "%d %s" % (int(value), str(unit))
else:
ReturnDict["type"] = 'int'
ReturnDict["value"] = value
return json.dumps(ReturnDict, sort_keys=False)
elif isinstance(value, float):
if not NoString:
return "%.2f %s" % (float(value), str(unit))
else:
ReturnDict = collections.OrderedDict()
ReturnDict["type"] = 'float'
ReturnDict["value"] = round(value, 2)
return json.dumps(ReturnDict, sort_keys=False)
else:
self.LogError("Unsupported type in ValueOut: " + str(type(value)))
return DefaultReturn
except Exception as e1:
self.LogErrorLine("Error in ValueOut: " + str(e1))
return DefaultReturn

#------------ MySupport::GetDispatchItem -----------------------------------
def GetDispatchItem(self, item):

Expand All @@ -153,7 +185,7 @@ def GetDispatchItem(self, item):
elif isinstance(item, float):
return str(item)
else:
self.LogError("Unable to convert type %s in GetDispatchItem" % type(item))
self.LogError("Unable to convert type %s in GetDispatchItem" % str(type(item)))
self.LogError("Item: " + str(item))
return ""

Expand All @@ -179,11 +211,11 @@ def ProcessDispatch(self, node, InputBuffer, indent=0):
NewDict2 = collections.OrderedDict()
InputBuffer[key].append(self.ProcessDispatch(listitem, NewDict2))
else:
self.LogError("Invalid type in ProcessDispatch %s " % type(node))
self.LogError("Invalid type in ProcessDispatch %s " % str(type(node)))
else:
InputBuffer[key] = self.GetDispatchItem(item)
else:
self.LogError("Invalid type in ProcessDispatch %s " % type(node))
self.LogError("Invalid type in ProcessDispatch %s " % str(type(node)))

return InputBuffer

Expand All @@ -208,11 +240,11 @@ def ProcessDispatchToString(self, node, InputBuffer, indent = 0):
elif isinstance(listitem, str):
InputBuffer += ((" " * (indent +1)) + self.GetDispatchItem(listitem) + "\n")
else:
self.LogError("Invalid type in ProcessDispatchToString %s %s (2)" % (key, type(listitem)))
self.LogError("Invalid type in ProcessDispatchToString %s %s (2)" % (key, str(type(listitem))))
else:
InputBuffer += ((" " * indent) + str(key) + " : " + self.GetDispatchItem(item) + "\n")
else:
self.LogError("Invalid type in ProcessDispatchToString %s " % type(node))
self.LogError("Invalid type in ProcessDispatchToString %s " % str(type(node)))
return InputBuffer

#---------- Controller::GetNumBitsChanged----------------------------------
Expand Down
Loading

0 comments on commit f0d6e91

Please sign in to comment.