Skip to content

Commit 539afa0

Browse files
authored
Merge pull request #3 from jgyates/master
update to jgyates
2 parents e8ca5b5 + f0d6e91 commit 539afa0

20 files changed

+1473
-1200
lines changed

.github/ISSUE_TEMPLATE.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,6 @@ You can submit your registers from the Monitor page on the web interface.
3434

3535
### Your Environment
3636

37-
- Genereator Model: {Please write here}
37+
- Generator Model: {Please write here}
3838
- Generator Registers: {Please write here}
3939
- Genmon Version: {Please write here}

changelog.md

+22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,28 @@
11
# Changelog
22
All notable changes to this project will be documented in this file. Major releases are documented [here](https://github.com/jgyates/genmon/releases)
33

4+
5+
## V1.11.8 - 2018-10-16
6+
- Improvements for genmqtt.py to allow for integer and float values to be passed as JSON strings
7+
- 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.
8+
9+
## V1.11.7 - 2018-10-13
10+
- Add new remote command to reset the current alarm (see Maintenance page)
11+
- Fixed bug in power log for H-100, if you experience problems, reset the power log or delete the file kwlog.txt and restart.
12+
- Moved Update Software in the web interface to the About page
13+
- Moved Submit Registers in the web interface to the About page
14+
- Added Submit Log Files button on the About page
15+
- Added change log to the web interface About page
16+
17+
## V1.11.6 - 2018-10-13
18+
- 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.
19+
- Added more error checking / logging in modbus protocol code. This makes serial over TCP more robust.
20+
- Fixed minor issue in genlog.py
21+
- Improved error logging in myclient.py
22+
23+
## V1.11.5 - 2018-10-12
24+
- Removed restart on I/O error in genserv.
25+
426
## V1.11.4 - 2018-10-11
527
- Corrected bug in type in genserv.py. Corrects problem with settings page not displaying.
628

conf/genmqtt.conf

+6-1
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,16 @@ flush_interval = 0
3939
# to make the path be Home/generator.
4040
root_topic =
4141

42+
# Optional. This value, if true will return numeric values in the Status topic
43+
# as a JSON string which can be converted to an object with integer or float
44+
# values. This applies to items in on the Status page only.
45+
numeric_json = False
46+
4247
# Optional. By default the program will attempt to export all text data that is
4348
# exported by genmon (see the web interface for details). The blacklist
4449
# entry is a way to skip some values that are updated frequently that may not
4550
# be useful in your MQTT based system. For example the modbus packet count
4651
# be suppressed from MQTT by adding "Packet Count" in the line below, or
4752
# "Platform Stats" will exclude all data in the Platform Stats section.
4853
# Multiple entries are separated by commas.
49-
blacklist = Log,System Uptime,Packet Count,Run Time,Monitor Time,Generator Time,External Data
54+
blacklist = Monitor,Log,System Uptime,Packet Count,Run Time,Monitor Time,Generator Time,External Data

genloader.py

+29-9
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,6 @@ def InstallLibrary(self, libraryname):
150150
self.LogInfo("Error installing module: " + libraryname + ": "+ str(e1), LogLine = True)
151151
return False
152152
#---------------------------------------------------------------------------
153-
def LogInfo(self, message, LogLine = False):
154-
155-
if not LogLine:
156-
self.LogError(message)
157-
else:
158-
self.LogErrorLine(message)
159-
self.LogConsole(message)
160-
#---------------------------------------------------------------------------
161153
def ValidateConfig(self):
162154

163155
ErrorOccured = False
@@ -339,7 +331,7 @@ def StartModules(self):
339331
return False
340332
return not ErrorOccured
341333
#---------------------------------------------------------------------------
342-
def LoadModule(self, modulename, args = None):
334+
def LoadModuleAlt(self, modulename, args = None):
343335
try:
344336
self.LogConsole("Starting " + modulename)
345337
# to load as a background process we just use os.system since Popen
@@ -356,6 +348,34 @@ def LoadModule(self, modulename, args = None):
356348
return False
357349

358350
#---------------------------------------------------------------------------
351+
def LoadModule(self, modulename, args = None):
352+
try:
353+
self.LogConsole("Starting " + modulename)
354+
355+
try:
356+
from subprocess import DEVNULL # py3k
357+
except ImportError:
358+
import os
359+
DEVNULL = open(os.devnull, 'wb')
360+
361+
if not len(args):
362+
args = None
363+
364+
if "genserv.py" in modulename:
365+
OutputStream = DEVNULL
366+
else:
367+
OutputStream = subprocess.PIPE
368+
if args == None:
369+
# close_fds=True
370+
pid = subprocess.Popen([sys.executable, modulename], stdout=OutputStream, stderr=OutputStream, stdin=OutputStream)
371+
else:
372+
pid = subprocess.Popen([sys.executable, modulename, args], stdout=OutputStream, stderr=OutputStream, stdin=OutputStream)
373+
return True
374+
375+
except Exception as e1:
376+
self.LogInfo("Error loading module: " + str(e1), LogLine = True)
377+
return False
378+
#---------------------------------------------------------------------------
359379
def UnloadModule(self, modulename, HardStop = False):
360380
try:
361381
self.LogConsole("Stopping " + modulename)

genlog.py

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ def LogDataToFile(fileName, time, Event):
6969
address = arg
7070
elif opt in ("-f", "--filename"):
7171
fileName = arg
72+
fileName = fileName.strip()
7273

7374
console.error('Address is ' + address)
7475
console.error('Output file is ' + fileName)

genmon.py

+19-9
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
print("Error: " + str(e1))
2626
sys.exit(2)
2727

28-
GENMON_VERSION = "V1.11.4"
28+
GENMON_VERSION = "V1.11.8"
2929

3030
#------------ Monitor class ----------------------------------------------------
3131
class Monitor(mysupport.MySupport):
@@ -437,6 +437,7 @@ def ProcessCommand(self, command, fromsocket = False):
437437
"allregs_json" : [self.Controller.DisplayRegisters, (True, True), True], # display registers
438438
"logs_json" : [self.Controller.DisplayLogs, (True, True), True],
439439
"status_json" : [self.Controller.DisplayStatus, (True,), True],
440+
"status_num_json" : [self.Controller.DisplayStatus, (True,True), True],
440441
"maint_json" : [self.Controller.DisplayMaintenance, (True,), True],
441442
"monitor_json" : [self.DisplayMonitor, (True,), True],
442443
"weather_json" : [self.DisplayWeather, (True,), True],
@@ -783,8 +784,6 @@ def SocketWorkThread(self, conn):
783784

784785
try:
785786

786-
conn.settimeout(2) # only blok on recv for a small amount of time
787-
788787
statusstr = ""
789788
if self.Controller == None:
790789
outstr = "WARNING: System Initializing"
@@ -804,12 +803,18 @@ def SocketWorkThread(self, conn):
804803
while True:
805804
try:
806805
data = conn.recv(1024)
807-
if self.Controller == None:
808-
outstr = "Retry, System Initializing"
806+
if len(data):
807+
if self.Controller == None:
808+
outstr = "Retry, System Initializing"
809+
else:
810+
outstr = self.ProcessCommand(data, True)
811+
conn.sendall(outstr.encode())
809812
else:
810-
outstr = self.ProcessCommand(data, True)
811-
conn.sendall(outstr.encode())
813+
# socket closed remotely
814+
break
812815
except socket.timeout:
816+
if self.IsStopping:
817+
break
813818
continue
814819
except socket.error as msg:
815820
try:
@@ -820,9 +825,14 @@ def SocketWorkThread(self, conn):
820825
break
821826

822827
except socket.error as msg:
828+
self.LogError("Error in SocketWorkThread: " + str(msg))
829+
pass
830+
831+
try:
823832
self.ConnectionList.remove(conn)
824833
conn.close()
825-
834+
except:
835+
pass
826836
# end SocketWorkThread
827837

828838
#---------- interface for heartbeat server thread -------------------------
@@ -842,7 +852,7 @@ def InterfaceServerThread(self):
842852
while True:
843853
try:
844854
conn, addr = self.ServerSocket.accept()
845-
#self.printToString( 'Connected with ' + addr[0] + ':' + str(addr[1]))
855+
#self.LogError('Connected with ' + addr[0] + ':' + str(addr[1]))
846856
conn.settimeout(0.5)
847857
self.ConnectionList.append(conn)
848858
SocketThread = threading.Thread(target=self.SocketWorkThread, args = (conn,), name = "SocketWorkThread")

genmonlib/controller.py

+2
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,8 @@ def GetPowerHistory(self, CmdString, NoReduce = False):
953953
Items = line.split(",")
954954
if len(Items) != 2:
955955
continue
956+
# remove any kW labels that may be there
957+
Items[1] = self.removeAlpha(Items[1])
956958

957959
if Minutes:
958960
struct_time = time.strptime(Items[0], "%x %X")

genmonlib/generac_HPanel.py

+28-25
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,7 @@ def GetStartInfo(self, NoTile = False):
10111011
StartInfo["RemoteCommands"] = False
10121012
StartInfo["RemoteButtons"] = False
10131013
StartInfo["PowerGraph"] = self.PowerMeterIsSupported()
1014-
StartInfo["ExerciseControls"] = not self.SmartSwitch
1014+
StartInfo["ExerciseControls"] = False # self.SmartSwitch
10151015

10161016
if not NoTile:
10171017
StartInfo["pages"] = {
@@ -1153,7 +1153,7 @@ def DisplayMaintenance (self, DictOut = False):
11531153
return ""
11541154

11551155
#------------ HPanel::DisplayStatus ----------------------------------------
1156-
def DisplayStatus(self, DictOut = False):
1156+
def DisplayStatus(self, DictOut = False, JSONNum = False):
11571157

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

11721172

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

11761176
Engine["Current Status"] = self.GetParameterString(RegisterEnum.STATUS_INFO_START, RegisterEnum.STATUS_INFO_END)
11771177
Engine["Previous Status"] = self.GetParameterString(RegisterEnum.STATUS_2_INFO_START, RegisterEnum.STATUS_2_INFO_END)
11781178
Engine["Switch State"] = self.GetSwitchState()
11791179
Engine["Engine State"] = self.GetEngineState()
1180-
Engine["Output Power"] = self.GetPowerOutput()
1181-
Engine["Output Power Factor"] = self.GetParameter(RegisterEnum.TOTAL_PF, Divider = 100.0)
1182-
Engine["RPM"] = self.GetParameter(RegisterEnum.OUTPUT_RPM)
1183-
Engine["Frequency"] = self.GetParameter(RegisterEnum.OUTPUT_FREQUENCY, "Hz", 10.0)
1184-
Engine["Throttle Position"] = self.GetParameter(RegisterEnum.THROTTLE_POSITION, "Stp")
1185-
Engine["Coolant Temp"] = self.GetParameter(RegisterEnum.COOLANT_TEMP, "F")
1186-
Engine["Coolant Level"] = self.GetParameter(RegisterEnum.COOLANT_LEVEL, "Stp")
1187-
Engine["Oil Pressure"] = self.GetParameter(RegisterEnum.OIL_PRESSURE, "psi")
1188-
Engine["Oil Temp"] = self.GetParameter(RegisterEnum.OIL_TEMP, "F")
1189-
Engine["Fuel Level"] = self.GetParameter(RegisterEnum.FUEL_LEVEL)
1190-
Engine["Oxygen Sensor"] = self.GetParameter(RegisterEnum.O2_SENSOR)
1191-
Engine["Current Phase A"] = self.GetParameter(RegisterEnum.CURRENT_PHASE_A,"A")
1192-
Engine["Current Phase B"] = self.GetParameter(RegisterEnum.CURRENT_PHASE_B,"A")
1193-
Engine["Current Phase C"] = self.GetParameter(RegisterEnum.CURRENT_PHASE_C,"A")
1194-
Engine["Average Current"] = self.GetParameter(RegisterEnum.AVG_CURRENT,"A")
1195-
Engine["Voltage A-B"] = self.GetParameter(RegisterEnum.VOLTS_PHASE_A_B,"V")
1196-
Engine["Voltage B-C"] = self.GetParameter(RegisterEnum.VOLTS_PHASE_B_C,"V")
1197-
Engine["Voltage C-A"] = self.GetParameter(RegisterEnum.VOLTS_PHASE_C_A,"V")
1198-
Engine["Average Voltage"] = self.GetParameter(RegisterEnum.AVG_VOLTAGE,"V")
1199-
Engine["Air Fuel Duty Cycle"] = self.GetParameter(RegisterEnum.A_F_DUTY_CYCLE, Divider = 10.0)
1180+
Engine["Output Power"] = self.ValueOut(self.GetPowerOutput(ReturnFloat = True), "kW", JSONNum)
1181+
Engine["Output Power Factor"] = self.ValueOut(self.GetParameter(RegisterEnum.TOTAL_PF, ReturnFloat = True, Divider = 100.0), "", JSONNum)
1182+
Engine["RPM"] = self.ValueOut(self.GetParameter(RegisterEnum.OUTPUT_RPM, ReturnInt = True), "", JSONNum)
1183+
Engine["Frequency"] = self.ValueOut(self.GetParameter(RegisterEnum.OUTPUT_FREQUENCY, ReturnFloat = True, Divider = 10.0), "Hz", JSONNum)
1184+
Engine["Throttle Position"] = self.ValueOut(self.GetParameter(RegisterEnum.THROTTLE_POSITION, ReturnInt = True), "Stp", JSONNum)
1185+
Engine["Coolant Temp"] = self.ValueOut(self.GetParameter(RegisterEnum.COOLANT_TEMP, ReturnInt = True), "F", JSONNum)
1186+
Engine["Coolant Level"] = self.ValueOut(self.GetParameter(RegisterEnum.COOLANT_LEVEL, ReturnInt = True), "Stp", JSONNum)
1187+
Engine["Oil Pressure"] = self.ValueOut(self.GetParameter(RegisterEnum.OIL_PRESSURE, ReturnInt = True), "psi", JSONNum)
1188+
Engine["Oil Temp"] = self.ValueOut(self.GetParameter(RegisterEnum.OIL_TEMP, ReturnInt = True), "F", JSONNum)
1189+
Engine["Fuel Level"] = self.ValueOut(self.GetParameter(RegisterEnum.FUEL_LEVEL, ReturnInt = True), "", JSONNum)
1190+
Engine["Oxygen Sensor"] = self.ValueOut(self.GetParameter(RegisterEnum.O2_SENSOR, ReturnInt = True), "", JSONNum)
1191+
Engine["Current Phase A"] = self.ValueOut(self.GetParameter(RegisterEnum.CURRENT_PHASE_A, ReturnInt = True), "A", JSONNum)
1192+
Engine["Current Phase B"] = self.ValueOut(self.GetParameter(RegisterEnum.CURRENT_PHASE_B,ReturnInt = True), "A", JSONNum)
1193+
Engine["Current Phase C"] = self.ValueOut(self.GetParameter(RegisterEnum.CURRENT_PHASE_C,ReturnInt = True), "A", JSONNum)
1194+
Engine["Average Current"] = self.ValueOut(self.GetParameter(RegisterEnum.AVG_CURRENT,ReturnInt = True), "A", JSONNum)
1195+
Engine["Voltage A-B"] = self.ValueOut(self.GetParameter(RegisterEnum.VOLTS_PHASE_A_B,ReturnInt = True), "V", JSONNum)
1196+
Engine["Voltage B-C"] = self.ValueOut(self.GetParameter(RegisterEnum.VOLTS_PHASE_B_C,ReturnInt = True), "V", JSONNum)
1197+
Engine["Voltage C-A"] = self.ValueOut(self.GetParameter(RegisterEnum.VOLTS_PHASE_C_A,ReturnInt = True), "V", JSONNum)
1198+
Engine["Average Voltage"] = self.ValueOut(self.GetParameter(RegisterEnum.AVG_VOLTAGE,ReturnInt = True), "V", JSONNum)
1199+
Engine["Air Fuel Duty Cycle"] = self.ValueOut(self.GetParameter(RegisterEnum.A_F_DUTY_CYCLE, ReturnFloat = True, Divider = 10.0), "", JSONNum)
12001200

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

1374-
return self.GetParameter(RegisterEnum.TOTAL_POWER_KW, "kW", ReturnFloat = ReturnFloat)
1374+
if ReturnFloat:
1375+
return self.GetParameter(RegisterEnum.TOTAL_POWER_KW, ReturnFloat = True)
1376+
else:
1377+
return self.GetParameter(RegisterEnum.TOTAL_POWER_KW, "kW", ReturnFloat = False)
13751378

13761379
#---------- HPanel:GetCommStatus -----------------------------------------
13771380
# return Dict with communication stats

0 commit comments

Comments
 (0)