Appendix N Genmon Supporting Other Controller Types - jgyates/genmon GitHub Wiki

Genmon Supporting Other Controller Types

Beginning with genmon V1.17.0, to support other types of generator controllers the software supports an extensible architecture that will allow for additional controllers to be defined in a JSON format file based on modbus registers and numeric and bit definitions within the modbus registers. If new controllers are defined, please submit them to the project. New JSON files can be added to genmon/data/controllers and the advanced settings page will display them as a configuration option. Double click the gear icon in the upper right of the web interface to access the Advanced Settings page. To use an existing custom controller:

  1. Set "Controller Type" to "custom" on the Advanced Settings page
  2. Select the custom controller type from the "Custom Controller Config File" setting on the Advanced Settings page
  3. Set the "Modbus slave address" to the modbus address used by the controller to communicate with genmon.

Some controllers, like the Briggs and Stratton GC-1032 may required additional settings to change on the controller. See this page for more details.

Currently Supported via the Custom Controller Interface:

Controller JSON File Description
Evolution Liquid Cooled Evolution_Liquid_Cooled.json Generac Evolution Liquid Cooled (Diesel)
Deep See Electronics Genset Controller Deepsea_controller.json https://www.deepseaelectronics.com/genset
Briggs & Stratton GC-1032 Controller Briggs_Stratton_GC-1032.json https://www.briggsandstratton.com/na/en_us/products/home-generators.html
Generac PowerZone 410 Controller Power_Zone_410.json https://www.generac.com/Industrial/GeneracIndustrialPower/media/library/A0001371117.pdf
ComAP Controller ComAp.json https://www.comap-control.com/products/controllers/ . Tested with ComAP IG-NT
Kohler APM603 Kohler_APM604.json https://powersystems.kohlerenergy.com/en/product/apm603

Remote Commands

Some controllers have remote commands for things like resetting alarms and remotely starting and stopping the generator. In some cases this functionality has been added to the custom controller configuration. Some controllers, for example the ComAp controller, require these commands to be enabled by the user via the controller interface before they can be used. If remote commands do not work on your controller, the consult your controller documentation.

How to Create Support for Additional Controllers

Know the modbus addresses

Use the modbusdump.py program in the OtherApps folder to validate either serial or serial over TCP communications with the controller. If you do not know the modbus address the controller uses you can potentially use this program to help determine the modbus address used. The genmon software will need to know the modbus address. Once you have added support via a JSON file or if you are using an exiting JSON file, set the controller modbus address on the Advanced Settings page.

Obtain the modbus register definitions for your controller.

Using this information you can create a JSON format file that can be added to the project that will allow the generator to be supported with genmon. Note that complex manipulation of modbus register data is not supported wit this method so displaying log files or operations that deal with time and date are not supported using the JSON method at this time. The JSON file format syntax is listed below.

Enable the Custom Controller Type

Enable the Custom Controller Type - To enable the support for a user defined controller, modify the following entry to your /etc/genmon.conf file or change this value from the advanced page in the web interface.

controllertype = custom
import_config_file = filename.json

where filename.json is a JSON formatted file (see below) in the genmon/data/controller directory. Note: These values can be set from the advanced settings page. Double click the gear icon in the web interface to access the advanced settings page.

Modbus Communications

To facilitate communication differences is some controllers the following settings are available if the default values of 9600,N,8 and 1 are not compatible with your controller:

  • Optionally, enable "Use Modbus FC4 instead of FC3" on the Advanced Setting page - This allows the use fo modbus function 4 instead of function 3 to read modbus registers (Used for Briggs and Stratton controllers)
  • Use serial over network connections instead of direct serial connections. This includes Modbus TCP and serial over IP variants
  • Optionally, Edit the /etc/genmon/genmon.conf file and add an entry named 'serial_baud_rate' and set it to the desired baud rate (e.g. serial_baud_rate=11520)
  • Optionally, Edit the /etc/genmon/genmon.conf file and add an entry named 'serial_parity' and set it to 1 for odd parity and 2 for even parity. Remove the entry for no parity
  • Optionally, Edit the /etc/genmon/genmon.conf file and add an entry named 'serial_one_point_five_stop_bits' and set it to True to use 1.5 stop bits. Remove the entry or set it to False for 1 stop bit
  • Optionally, Edit the /etc/genmon/genmon.conf file and add an entry named 'serial_rate' and set it to the serial data rate (i.e. 115200, 19200, etc_ if using serial communications (not TCP). Only do this if the rate is something other than 9600 baud. The default rate is 9600. You can also change this setting on the Advanced Settings Page of the web interface (double click the gear icon to access Advanced Setting)

JSON File Syntax

NOTE: Before you start to develop an new JSON file for a generator that is not currently supported, the first thing to do is to make a copy and rename an existing JSON file and change the name of the "controller_name" entry in the file. If you do not change the name of the file your changes will be overwritten when the software is updated.

The file format is standard JSON format. The file can be validated using an online JSON format checker like this one. If the format does not conform to the JSON standard genmon will not load properly.

The file contains a single JSON object. Within the objects are several other objects. Presently there are no nested objects past the first level objects supported. The high level objects supported are:

  • "controller_name" - The name displayed for the controller in the software
  • “rated_max_output_power_kw" - This can be an Integer value. For example a 22kW system would use 22 for this value
  • “rated_nominal_voltage" - Integer value. This is typically 240 for US singled phase. For three phase put the maximum voltage of the combined phase. This value is used to set the gauge markings.
  • "rated_nominal_rpm” - Integer value, typically 1500, 1800, 3000 or 3600
  • "rated_nominal_freq" - Integer value. Typically 60 or 50
  • "nominal_battery_voltage" - Integer value. Typically 12 or 24
  • "generator_phase" - The phase of the generator (i.e. 1 or 3). This is an integer value
  • "holding_registers" - an object of registers and the second parameter describing the register. The first parameter is the register address and must be a 4 digit hex values. At a minimum the second parameter must be an integer specifying the length of each register although additional information can be specified such as a text description of the register. Each register length must be multiples of 2. For additional data in the user interface the second parameter can be a nested object that contains "length" and "text". The "holding_registers" dict must contain all the holding registers that are read by the software. Registers that are written are not required to be in this object. If another object in the JSON file references a holding register to read, it must be defined in this object. These registers are read using the modbus read multiple register command (0x03). The modbus command to read input registers (0x04) can be used if the Advanced setting "Use Modbus FC4 instead of FC3" is enabled.
  • "coil_registers" - an object of registers representing the registers of the modbus holding registers (modbus function 1). Coil register are implemented in the modbus standard as a binary value (on or off / 1 or zero). This object is formatted like "holding_registers". The only differences are that this object represents the modbus coil registers used and the length of each coil register must be 1. If another object in the JSON file references a coil register to read, it must be defined in this object.
  • "input_registers" - an object of registers representing the registers of the modbus holding registers (modbus function 4). This object is formatted like "holding_registers". The only difference is that this object represents the modbus input registers used. If another object in the JSON file references an input register to read, it must be defined in this object.
  • "settime" - This optional object allows the date and time to be written to the controller. Genmon can sync the controller time to the time on the system running genmon and optionally make changes for daylight savings time if enabled in the settings. This object contains a list named "command_sequence" that contains descriptions of the hour, minute, month, year, day along with what modbus registers should be written. See the ./genmon/data/controller/Evolution_Liquid_Cooled.json example for details.

In addition to integer values the values of “rated_max_output_power_kw", “rated_nominal_voltage", "rated_nominal_rpm”, "rated_nominal_freq", "nominal_battery_voltage", and "generator_phase" can alternatively be a JSON object defining a register value (see examples in the repository). For example:

    "rated_max_output_power_kw":  {
        "reg": "0054",
        "mask": "7f00",
        "multiplier": 0.00390625,
        "type": "int",
        "title": "Nominal kW"
      }

If the values “rated_max_output_power_kw", “rated_nominal_voltage", "rated_nominal_rpm”, "rated_nominal_freq", "nominal_battery_voltage" can be set to non integer values, then the values for nominal kW, nominal line voltage, RPM, frequency and battery voltage will be used from the settings and advanced settings pages. For example if the JSON file looks like this:

    "nominal_battery_voltage": "Unknown"

then the value for nominal battery voltage will be set via the Advanced page.

The following JSON objects define logic conditions that can be performed on the resulting modbus data. All of the following objects consist of a single list of one or more condition objects. Some lists are evaluated as a single logic operation with multiple conditions (e.g. switch_state) and others are a list of multiple logic operations (e.g. status). A condition object is defined as a JSON object with the following members:

  • "reg" - modbus register. This value must be included in either holding_registers, input_registers or coil_registers and it's length is also defined there. This value is a 4 digit string formatted as a hex number (e.g. "01fe")
  • "reg_type" - If excluded, the default value is "holding". The other options are "input" or "coil". This specifies the type of modbus registers.
  • "title" - A Title for the object. For single logic operations the name of the object is the same. For multiple operations the name is unique for each object in the list.
  • "type" - The describes the type of interpretation on the modbus data. Valid entries for this field are:
    • "bits" - The modbus value is AND-ed with the mask. If the result is equal to the "value" field, the the "text" field is displayed.
    • "int" - Integer value. The modbus value is AND-ed with the mask and the resulting integer value is returned.
    • "float" - Float value. Both "float" and "int" types can use the following modifiers: "exec", "multiplier", "shiftleft" and "shiftright".
    • "bool" - Similar to "bits" except evaluated to zero (False) or non zero (True)
    • "regex" - If the regex type is specified a "regex" field is used. The "regex" field contains a regular expression string (e.g. "^(1[0-9a-f]|[1-9a-f])$") to compare against the modbus results. The modbus results are stored in a hex string (e.g. "00a4"). If the regular expression evaluation is a match the "text" field is returned. Nothing is returned if the regular expression is evaluated to False unless a "default" value is specified.
    • "list" - This denotes that a JSON list of other types listed is used.
    • "ascii" - This denotes an ASCII string or a series of ASCII characters.
  • "mask" - This is a string representing a hex number. A logical AND operation is performed between the mask value value and the value read from the modbus register. The result of this is used to get the end value of the modbus register. This "mask" allows bits that are zero to be ignored in further calculations.
  • "value" - Used for type "bits", see above
  • "temperature" - if the value is an "int" or "float" this optional value can be "celsius" or "fahrenheit". This value will be converted, if necessary based on the "Use Metric Units" global setting.
  • "text" - The text string returned if type "bits" or type "regex" result in a True state. "text is also used with the "default" modifier in "list" and "object_int_index" types.
  • "sensor" - Used for gauge and sensor objects. Defines the type of sensor. Valid sensor types are: batteryvolts,linevolts,current,power,frequency,rpm,fuel,level,position,temperature,pressure,powergraph. These values determine the type of gauge or graph displayed. Only one powergraph is supported.
  • "nominal" - Used for gauge and sensor objects. Defines the nominal value of a gauge.
  • "multiplier" - a value that multiplied by the modbus value. This modifier can be applied to "int", "float" (pre float conversion), "object_int_index" (before being used as an index). If you need to shift values that are formatted as hex you can use decimal multipliers, for example a multiplier of 0.00390625 is the same as 1/256 or dividing by 0x100 hex or shifting right by 8 bits). This operation is performed before conversion to an int, float, etc.
  • "shiftright" - shifts the modbus register right by the specified number of bits. This operation is performed before conversion to an int, float, etc.
  • "shiftleft" - shifts the modbus register left by the specified number of bits. This operation is performed before conversion to an int, float, etc.
  • "round" - this modifier, when used with type "float" will round to the number of decimal places. See the ./genmon/data/controller/ComAp.json example for details.
  • "ieee754" - This modifier can be applied to type "float". It will convert a given unisnged input to and IEEE-754 floating point value. "ieee754" can be "half" (16 bits), "single" (32 bits), or "double" (64 bits).
  • "separator" - If type "list" is used then a "separator" value can be used to join the items in the list into a string, separated by the character specified in this entry. See the file ./genmon/data/controller/Evolution_Liquid_Cooled.json
  • "format" - For list values, elements in the list can contain a format string (e.g. "%02d") in order to format values like minutes or seconds in time formats. The entire list can also be use the "format" modifier. See the file ./genmon/data/controller/Evolution_Liquid_Cooled.json
  • "exec" - This modifier will allow a string representing python code to be executed. The python code must store the results in a local variable named 'exec_out'. This modifier can be used with "int", "float", "list". For an example, see the file ./genmon/data/controller/Evolution_Liquid_Cooled.json
  • "include" - This modifier will include entries from the a base object named "include". See the ./genmon/data/controller/ComAp.json example for details.
  • "prepend_text" - If the value output is a string for a given object, the text sepcified by this entry will be prepended to the output.
  • "object_int_index" - This denotes an integer that is a look up into a specified object. See the ./genmon/data/controller/Evolution_Liquid_Cooled.json example for details.
  • "object_bit_index" - This allows a bit position of an integer to define a state. For a given object multiple states can be active. See the ./genmon/data/controller/ComAp.json example for details.
  • signed16 or signed32 - These operators can be applied to a type "int" and will convert the integer to a signed 16 or 32 bit integer if the value is true. See the file ./genmon/data/controller/Power_Zone_410.json
  • "default" - For single logic operations or lists. If a condition is evaluated as false, or a list has a length of zero then this value is returned.true, otherwise the objects "text" field will be used.

The following are the types of single condition lists (i.e. only one item in each list of objects is evaluated as true):

  • "switch_state" - Defines the conditions of the switch state.
  • "alarm_active" - (optional) Defines if an alarm is active. This is just an indicator if an alarm is active, not a specific alarm type.

The following are the types of multiple condition lists (i.e. all true entries are included in the returned status):

  • "status" - This list of objects determines the data displayed on the Status page of the web interface.
  • "maintenance" - This list of objects determines the data displayed on the Maintenance page of the web interface.
  • "alarm_conditions" - Defines the different types of alarms.
  • "generator_status" - Defines the generator status. This object is optional. For some controllers only switch_state and engine_state are needed.
  • "engine_state" - Defines the state of the engine.

Other types of objects:

  • "gauges" This list of objects defines the gauges displayed and the modbus values displayed.
  • "power" - Optional. This is defines the power output in kW. This is required to use the power log and estimated fuel consumption.
  • "fuel" - Optional. This defines the fuel level as a percentage. If this object is included then a fuel gauge will be added to sensors.
  • "run_hours" - This defines the run hours as an integer or float. This value provides the default run hours for the Service Journal.
  • "buttons" Optional. This list of objects defines the buttons displayed on the maintenance page and the modbus write commands that are issued if the button is pressed.
  • "linevoltage" - Optional. Utility line voltage. This value is used for determining when an outage occurs.
  • "outputvoltage" - Optional. Generator output voltage. This value is used if using external Current Transformers (CTs) to provide power. The current reading from the CT along with the generator output voltage is used to convert to power (assuming power is not provided by the controller registers)
  • "thresholdvoltage" - Optional. Can be an integer value or a JSON object defining a modbus register. This defines the line voltage level that signals the beginning of an outage
  • "pickupvoltage" - Optional. Can be an integer value or a JSON object defining a modbus register. This defines the line voltage level that signals the end of and outage
  • "datetime" - Optional. This is an object that describes the generator date and time. This can be in any format, but typically this is in "DayOfWeek Month DayofMonth, Year Hour:Min
  • "log_registers" - Optional. This object describes a range of registers that contain logs (e.g. alarm, run and service logs). This entry instructs genmon to read the described registers. The "logs" entry describes how the registers are displayed on the logs page in the user interface. See the file ./genmon/data/controller/Evolution_Liquid_Cooled.json
  • "logs" - Optional. This object describes how the log registers are displayed on the Logs page in the user interface. See the file ./genmon/data/controller/Evolution_Liquid_Cooled.json
  • "identity" - Optional. This is a register used to help identify the controller with a unique signature in the modbus registers. See the file ./genmon/data/controller/Power_Zone_410.json
  • "maintenance_due" - Optional. This object will evaluate to a returned string if maintenance is due, otherwise it will return nothing. See the file ./genmon/data/controller/Power_Zone_410.json

Outage log: The outage log is enable if linevoltage, thresholdvoltage and pickupvoltage are defined.

gauges

The gauges member of the JSON object is an array of objects. Each object in the array represents a gauge or graph.

    "gauges": [
      {
          "reg": "0405",
          "mask": "ffff",
          "multiplier": 0.1,
          "type": "float",
          "title": "Battery Voltage",
          "units": "V",
          "sensor": "batteryvolts",
          "nominal": 24,
          "values": [0, 8, 10, 34, 36, 44],
          "maximum": 44
      },
      {
          "reg": "0424",
          "mask": "ffff",
          "multiplier": 1,
          "type": "int",
          "title": "Utility Voltage",
          "units": "V",
          "sensor": "linevolts",
          "nominal": 240
      },
      {
          "reg": "0408",
          "mask": "ffff",
          "multiplier": 1,
          "type": "int",
          "title": "Output Voltage",
          "units": "V",
          "sensor": "linevolts",
          "nominal": 240
      }

The 'sensor' member of each gauge in the list must be one of the following values: batteryvolts, linevolts, current, power, frequency, fuel, level, position, temperature, pressure, powergraph, rpm or wifi.

For a sensor of type "batteryvolts", "linevolts", "power"/"powergraph" or "frequency", the the nominal value is "Unknown" then the unknown value will attempt to be substituted for "nominal_battery_voltage", "rated_nominal_voltage", “rated_max_output_power_kw" or "rated_nominal_freq". If type "current" has a nominal value of "Unknown" then rated_nominal_voltage and “rated_max_output_power_kw will be used to calculate the rated current.

There can only be one gauge with a sensor value of 'powergraph'. The register value of the 'powergraph' must correspond to the power output power of the generator.

The members of each gauge object provide information that helps the software display the gauge data properly. The 'reg', 'mask', 'multiplier' and "type" properties are defined above. The 'units' and 'title' are used to mark the units and label assigned to the gauge. The 'sensor' value is used to set the markings on the graph. The 'nominal' and 'maximum' values along with the 'values' array can override some of the default values for each sensor type to help customize the gauge display for situations where the default values are not appropriate.

buttons

    "buttons" : [
      {
          "onewordcommand" : "stop",
          "title" : "Stop Mode",
          "command_sequence" : [
                                 {
                                   "reg": "1008",
                                   "value": ["8B", "74", "74", "8b"]
                                 }
                               ]
      },
      {
          "onewordcommand" : "auto",
          "title" : "Auto Mode",
          "command_sequence" : [
                                 {
                                   "reg": "0004",
                                   "value": "0000"
                                 },
                                 {
                                   "reg": "0003",
                                   "value": "0001"
                                 }
                               ]
      }

The 'buttons' object defines a list of objects. Each object in the list is a command that can be issued by the software. Each command object in the list has three objects:

  • 'onewordcommand' - used internally by the software to identify the command. This must be a single word (no spaces) and be unique in the list of buttons.
  • 'title' - This defines the text on the button that is displayed on the Maintenance page in the web interface.
  • 'command_sequence' - This is a list that defines write commands that are sent to the controller. The list must have at least one object. Each object in the list defines a single modbus write command. The 'reg' member of each command object contains a hex string that represent the modbus address to write using modubs Write Multiple Registers (0x10) command. This register value does not have to be in the 'holding_registers' object listed above since this register is written, not read. The 'value' item in each command object can either be a decimal value (i.e. no quotes) or a quoted hex string (e.g "8b"). The 'value' item can also be a list of decimal or quoted hex strings. The list is used to force the command to be issued in one modbus command (i.e. write multiple registers with more than one 16 bit value written at a time). If the non-list version is used and multiple commands are in the 'command_sequence' each command will be issued back to back, but not as a single modbus transaction. This flexibility is offered since some controllers expect the commands to be issued in different write sequences.

If a button needs to have a user specified parameter then you can use a modified version of command_sequence entries. An user input will be provided on the Maintenance page of the web interface if and entry in the command sequence does not have a "value" but instead has an "input_title" and "type" entries. See the comments in the file ./genmon/data/controller/Evolution_Liquid_Cooled.json for details.

SNMP addon program

SNMP is supported with custom controllers. To allow the custom controller to work with the SNMP genmon add on program, another JSON file must be created in the ~./genmon/data/mib folder. This file must be named the same as the controller file, but the contents is formatted differently. See the file ./genmon/data/mib/Evolution_Liquid_Cooled.json for details on the format and the wiki entry on the SNMP addon for details on SNMP OID numbering.

⚠️ **GitHub.com Fallback** ⚠️