Categories
Food stuff.

Larb Chicken Cups

Also known as Larb Gai.

Easy to make, fucking delicious, and relatively “healthy” to booth.
This recipe isn’t particularly authentic, but it gets you 95% of the way there in 15 minutes or less.

Serves 2-4.

Double recipe if required, leftovers are delicious when cold.

  • 2 tablespoons vegetable oil
  • 4 garlic cloves (thinly sliced)
  • 500g chicken mince
  • Sauce:
    • 1/2 teaspoon sugar
    • 2 tablespoons fish sauce
    • 2 limes, juiced
    • 1/4 cup of sweet chilli sauce
  • Veggie Bowl (mix these together before cooking):
    • 1-2 red chilies (thinly sliced) or 2 tablespoons of fresh chilli paste.
    • 3 spring onions (thinly sliced)
    • 1/4 cup coriander (roughly chopped) – optional.
    • 1/2 cup fresh mint (roughly chopped)
    • 1 large white onion (thinly sliced)
  • salt (optional)
  • iceberg lettuce (or any other lettuce with large “cups”)
  • White mung bean sprouts
  • Sriracha Sauce
  • White rice (optional)
  1. Heat your wok over high heat and add 2 tablespoons of oil, add the ground chicken. 
  2. Stir-fry until the chicken is browned and crispy, and add in your sauce.
    • if chicken isn’t getting brown and crispy, throw in some more oil and let the meat sit on high heat.
  3. Stir-fry for another minute, then add your veggie bowl.
  4. Stir-fry for one more minute, and then taste for seasoning – ie, add salt or more chili, sugar, fish sauce, and/or lime juice to your taste if needed.
  5. Serve in lettuce cups topped with bean sprouts and sriracha sauce.
    • Optional – serve with white rice, if that’s your thing.

Categories
Uncategorized

Batrium + Mate3 Grafana JSON Model

For use displaying Batrium and Mate3 output data in Grafana.

{
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": "-- Grafana --",
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "type": "dashboard"
      }
    ]
  },
  "editable": true,
  "gnetId": null,
  "graphTooltip": 0,
  "id": 2,
  "links": [],
  "panels": [
    {
      "datasource": "Batrium",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "custom": {},
          "decimals": 1,
          "mappings": [],
          "max": 100,
          "min": 0,
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "dark-red",
                "value": null
              },
              {
                "color": "dark-orange",
                "value": 10
              },
              {
                "color": "dark-yellow",
                "value": 20
              },
              {
                "color": "light-yellow",
                "value": 30
              },
              {
                "color": "light-green",
                "value": 40
              },
              {
                "color": "semi-dark-green",
                "value": 50
              },
              {
                "color": "dark-green",
                "value": 60
              },
              {
                "color": "dark-green",
                "value": 70
              },
              {
                "color": "dark-green",
                "value": 80
              },
              {
                "color": "dark-green",
                "value": 90
              },
              {
                "color": "dark-green",
                "value": 100
              }
            ]
          },
          "unit": "percent"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 6,
        "w": 8,
        "x": 0,
        "y": 0
      },
      "hideTimeOverride": true,
      "id": 34,
      "options": {
        "displayMode": "lcd",
        "orientation": "vertical",
        "reduceOptions": {
          "calcs": [
            "last"
          ],
          "fields": "",
          "values": false
        },
        "showUnfilled": true
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "alias": "State of Charge",
          "groupBy": [],
          "measurement": "Shunt_Cap_F_E_SOC",
          "orderByTime": "ASC",
          "policy": "default",
          "query": "SELECT mean(\"SOC\") FROM \"Shunt_Cap_F_E_SOC\" WHERE $timeFilter GROUP BY time(1m) fill(null)\n\n",
          "rawQuery": false,
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "SOC"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": "30m",
      "timeShift": null,
      "title": "State of Charge",
      "type": "bargauge"
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": "Batrium",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          }
        },
        "overrides": []
      },
      "fill": 4,
      "fillGradient": 0,
      "gridPos": {
        "h": 6,
        "w": 16,
        "x": 8,
        "y": 0
      },
      "hiddenSeries": false,
      "hideTimeOverride": false,
      "id": 44,
      "legend": {
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "show": false,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 3,
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "7.3.7",
      "pointradius": 2,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "groupBy": [],
          "measurement": "Shunt_C_V_W",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Watts"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        }
      ],
      "thresholds": [],
      "timeFrom": "24h",
      "timeRegions": [],
      "timeShift": null,
      "title": "Total Power In/Out",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    },
    {
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "custom": {},
          "decimals": 2,
          "mappings": [],
          "max": 3000,
          "min": -3000,
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "dark-red",
                "value": null
              },
              {
                "color": "semi-dark-red",
                "value": -1
              },
              {
                "color": "dark-green",
                "value": 1
              }
            ]
          },
          "unit": "watt"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 6,
        "w": 8,
        "x": 0,
        "y": 6
      },
      "hideTimeOverride": true,
      "id": 17,
      "options": {
        "displayMode": "lcd",
        "orientation": "vertical",
        "reduceOptions": {
          "calcs": [
            "last"
          ],
          "fields": "",
          "values": false
        },
        "showUnfilled": true
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "groupBy": [],
          "measurement": "Shunt_C_V_W",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Watts"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "Power In/Out of Batteries",
      "type": "bargauge"
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": "Mate3",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          }
        },
        "overrides": []
      },
      "fill": 4,
      "fillGradient": 4,
      "gridPos": {
        "h": 6,
        "w": 16,
        "x": 8,
        "y": 6
      },
      "hiddenSeries": false,
      "hideTimeOverride": false,
      "id": 47,
      "legend": {
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "show": false,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 3,
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "7.3.7",
      "pointradius": 2,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "groupBy": [
            {
              "params": [
                "$interval"
              ],
              "type": "time"
            }
          ],
          "measurement": "totalinv",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "totalinv"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "mean"
              }
            ]
          ],
          "tags": []
        }
      ],
      "thresholds": [],
      "timeFrom": "24h",
      "timeRegions": [],
      "timeShift": null,
      "title": "House Power Usage",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "watt",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    },
    {
      "datasource": "Batrium",
      "fieldConfig": {
        "defaults": {
          "color": {
            "mode": "thresholds"
          },
          "custom": {
            "align": null,
            "filterable": false
          },
          "decimals": 2,
          "links": [],
          "mappings": [],
          "max": 3.6,
          "min": 2.8,
          "thresholds": {
            "mode": "percentage",
            "steps": [
              {
                "color": "dark-red",
                "value": null
              },
              {
                "color": "semi-dark-red",
                "value": 2
              },
              {
                "color": "dark-orange",
                "value": 3
              },
              {
                "color": "semi-dark-orange",
                "value": 4
              },
              {
                "color": "light-yellow",
                "value": 5
              },
              {
                "color": "light-green",
                "value": 6
              },
              {
                "color": "semi-dark-green",
                "value": 7
              },
              {
                "color": "dark-green",
                "value": 8
              },
              {
                "color": "dark-green",
                "value": 9
              },
              {
                "color": "dark-green",
                "value": 10
              }
            ]
          },
          "unit": "volt"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 6,
        "w": 8,
        "x": 0,
        "y": 12
      },
      "id": 26,
      "options": {
        "displayMode": "lcd",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "last"
          ],
          "fields": "",
          "values": false
        },
        "showUnfilled": true
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "alias": "",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell1"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell2",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "B",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell2"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell3",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "C",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell3"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell4",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "D",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell4"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell5",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "E",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell5"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell6",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "F",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell6"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell7",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "G",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell7"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell8",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "H",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell8"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell9",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "I",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell9"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell10",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "J",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell10"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell11",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "K",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell11"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell12",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "L",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "Cell12"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell13",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "M",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "CELL13"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell14",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "N",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "CELL14"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell15",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "O",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "CELL15"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        },
        {
          "alias": "Cell16",
          "groupBy": [],
          "measurement": "Cell_Voltage",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "P",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "CELL16"
                ],
                "type": "field"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "Cell Voltages",
      "transformations": [],
      "type": "bargauge"
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": "Batrium",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          }
        },
        "overrides": []
      },
      "fill": 0,
      "fillGradient": 1,
      "gridPos": {
        "h": 6,
        "w": 16,
        "x": 8,
        "y": 12
      },
      "hiddenSeries": false,
      "hideTimeOverride": false,
      "id": 46,
      "legend": {
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "show": true,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 3,
      "nullPointMode": "null",
      "options": {
        "alertThreshold": true
      },
      "percentage": false,
      "pluginVersion": "7.3.7",
      "pointradius": 2,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "groupBy": [
            {
              "params": [
                "15m"
              ],
              "type": "time"
            }
          ],
          "measurement": "Shunt_Cap_F_E_SOC",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "SOC"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "mean"
              }
            ]
          ],
          "tags": []
        }
      ],
      "thresholds": [],
      "timeFrom": "24h",
      "timeRegions": [],
      "timeShift": null,
      "title": "State of Charge",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "percent",
          "label": null,
          "logBase": 1,
          "max": "100",
          "min": "0",
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    },
    {
      "datasource": "Mate3",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "watt"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 0,
        "y": 18
      },
      "id": 37,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "mean"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "alias": "Inverter kW",
          "groupBy": [],
          "measurement": "inv1",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "inv1kw"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "INV1",
      "type": "stat"
    },
    {
      "datasource": "Mate3",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "watt"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 4,
        "y": 18
      },
      "id": 38,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "mean"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "alias": "Inverter kW",
          "groupBy": [],
          "measurement": "inv2",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "inv2kw"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "INV2",
      "type": "stat"
    },
    {
      "datasource": "Mate3",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "watt"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 8,
        "y": 18
      },
      "id": 39,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "mean"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "alias": "Inverter kW",
          "groupBy": [],
          "measurement": "inv3",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "inv3kw"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "INV3",
      "type": "stat"
    },
    {
      "datasource": "Batrium",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "decimals": 2,
          "mappings": [
            {
              "from": "-1",
              "id": 0,
              "operator": "",
              "text": "Presently Charging",
              "to": "-1000000",
              "type": 2,
              "value": "-1"
            }
          ],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "dark-green",
                "value": null
              },
              {
                "color": "dark-green",
                "value": 80
              }
            ]
          },
          "unit": "m"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 12,
        "y": 18
      },
      "id": 32,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "last"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "groupBy": [],
          "measurement": "EST-Full_Empty_Min",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "EDE"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "Est. to Empty",
      "type": "stat"
    },
    {
      "cacheTimeout": null,
      "datasource": "Batrium",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "rgb(255, 255, 255)",
                "value": null
              }
            ]
          }
        },
        "overrides": [
          {
            "matcher": {
              "id": "byName",
              "options": "Status"
            },
            "properties": [
              {
                "id": "displayName",
                "value": "Charging"
              }
            ]
          }
        ]
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 16,
        "y": 18
      },
      "id": 20,
      "interval": null,
      "links": [],
      "maxDataPoints": 100,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "last"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "alias": "Status",
          "groupBy": [
            {
              "params": [
                "$__interval"
              ],
              "type": "time"
            },
            {
              "params": [
                "null"
              ],
              "type": "fill"
            }
          ],
          "measurement": "Shunt_Status",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "SS"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "distinct"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "Status",
      "type": "stat"
    },
    {
      "datasource": "Batrium",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "decimals": 2,
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "semi-dark-red",
                "value": null
              },
              {
                "color": "dark-red",
                "value": 2.8
              },
              {
                "color": "dark-orange",
                "value": 2.9
              },
              {
                "color": "super-light-yellow",
                "value": 3
              },
              {
                "color": "super-light-green",
                "value": 3.2
              },
              {
                "color": "light-green",
                "value": 3.3
              },
              {
                "color": "semi-dark-green",
                "value": 3.4
              },
              {
                "color": "dark-green",
                "value": 3.5
              },
              {
                "color": "dark-green",
                "value": 3.5
              },
              {
                "color": "dark-green",
                "value": 3.6
              }
            ]
          },
          "unit": "volt"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 20,
        "y": 18
      },
      "id": 13,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "last"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "groupBy": [],
          "measurement": "Cell_Min_Max_Avg",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "AvCV"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "Cell Av V",
      "type": "stat"
    },
    {
      "datasource": "Mate3",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "dark-red",
                "value": null
              },
              {
                "color": "#EAB839",
                "value": 1
              }
            ]
          },
          "unit": "watt"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 0,
        "y": 21
      },
      "id": 42,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "mean"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "alias": "Total PV in",
          "groupBy": [],
          "measurement": "totalpv",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "totalpv"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "Total PV in",
      "type": "stat"
    },
    {
      "datasource": "Mate3",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "watt"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 4,
        "y": 21
      },
      "id": 41,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "mean"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "alias": "Inverter kW",
          "groupBy": [],
          "measurement": "mx60",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "mx60"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "FX60",
      "type": "stat"
    },
    {
      "datasource": "Mate3",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "watt"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 8,
        "y": 21
      },
      "id": 40,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "mean"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "alias": "Inverter kW",
          "groupBy": [],
          "measurement": "fx60",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "fx60"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "MX60",
      "type": "stat"
    },
    {
      "datasource": "Batrium",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "decimals": 2,
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "dark-green",
                "value": 80
              }
            ]
          },
          "unit": "m"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 12,
        "y": 21
      },
      "id": 11,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "lastNotNull"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "groupBy": [],
          "measurement": "EST-Full_Empty_Min",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "EDF"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "Est. to Full",
      "type": "stat"
    },
    {
      "datasource": "Batrium",
      "fieldConfig": {
        "defaults": {
          "custom": {},
          "decimals": 2,
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              },
              {
                "color": "red",
                "value": 80
              }
            ]
          },
          "unit": "volt"
        },
        "overrides": []
      },
      "gridPos": {
        "h": 3,
        "w": 4,
        "x": 16,
        "y": 21
      },
      "id": 18,
      "options": {
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto",
        "reduceOptions": {
          "calcs": [
            "last"
          ],
          "fields": "",
          "values": false
        },
        "textMode": "auto"
      },
      "pluginVersion": "7.3.7",
      "targets": [
        {
          "groupBy": [],
          "measurement": "Shunt_C_V_W",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "ShuntV"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "timeFrom": null,
      "timeShift": null,
      "title": "Shunt V",
      "type": "stat"
    }
  ],
  "refresh": "10s",
  "schemaVersion": 26,
  "style": "dark",
  "tags": [],
  "templating": {
    "list": []
  },
  "time": {
    "from": "2021-01-17T14:51:22.998Z",
    "to": "2021-01-18T14:51:22.998Z"
  },
  "timepicker": {
    "refresh_intervals": [
      "10s",
      "1m",
      "5m",
      "15m",
      "30m"
    ]
  },
  "timezone": "",
  "title": "Batrium Fixed",
  "uid": "v-DloQkMzPeNiS",
  "version": 68
}

Categories
Uncategorized

Batrium node-red JSON

For use with ingesting Batrium UDP data into node-red

[
    {
        "id": "383cb2f7.2caede",
        "type": "udp in",
        "z": "e6fd3a1c.5e9548",
        "name": "listener",
        "iface": "",
        "port": "18542",
        "ipv": "udp4",
        "multicast": "false",
        "group": "",
        "datatype": "buffer",
        "x": 50,
        "y": 40,
        "wires": [
            [
                "1454f5c0.1322ca"
            ]
        ]
    },
    {
        "id": "1454f5c0.1322ca",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "All Message Type numbers to Topic",
        "func": "msg.Topic = (msg.payload[2].toString(16).toUpperCase() + msg.payload[1].toString(16).toUpperCase())\nreturn\tmsg;\t\t\n\t\t\t\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 280,
        "y": 40,
        "wires": [
            [
                "d1a55ffb.c877a",
                "2af1bf8b.3e7b5"
            ]
        ]
    },
    {
        "id": "d1a55ffb.c877a",
        "type": "switch",
        "z": "e6fd3a1c.5e9548",
        "name": "Split the messages by type",
        "property": "Topic",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "415A",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4232",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "3E32",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "3F33",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4732",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4932",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "6131",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "5732",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4032",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "5432",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "7857",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "5632",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4A35",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4B35",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4C33",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4D33",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "5334",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4F33",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "5033",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "5158",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "5258",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4E58",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "5831",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "6831",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "5431",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4732",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "4d34",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "6132",
                "vt": "str"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 28,
        "x": 160,
        "y": 320,
        "wires": [
            [
                "9781b06a.53081"
            ],
            [
                "86897149.75de7"
            ],
            [
                "8f7d9f6b.5e7fa"
            ],
            [
                "7c28d81b.c0dd38"
            ],
            [],
            [
                "d1133f4a.3ef44"
            ],
            [
                "d2fa3827.0fb158"
            ],
            [
                "40d3fdc.2a54504"
            ],
            [
                "6ba51319.a7a48c"
            ],
            [
                "1704d7ce.245b58"
            ],
            [
                "aeea1ecd.3c858"
            ],
            [
                "122c8b3f.160005"
            ],
            [
                "bc35aeeb.93ab7"
            ],
            [
                "31f8d71a.f97f68"
            ],
            [
                "6bbf2b60.9ce744"
            ],
            [
                "a7cdb5ee.7c66c8"
            ],
            [
                "bc74a308.cfe11"
            ],
            [
                "a3320528.870448"
            ],
            [
                "84398b42.b2f578"
            ],
            [
                "66113e17.06931"
            ],
            [
                "d0a120ad.f8edd"
            ],
            [
                "3f60dd09.a9d822"
            ],
            [
                "672f0abe.f9af24"
            ],
            [
                "fa326eca.690b8"
            ],
            [
                "15f71030.bd9eb"
            ],
            [
                "34dd4fa2.32065"
            ],
            [
                "17a67e5b.e13952"
            ],
            [
                "e69dec4b.f16a1"
            ]
        ]
    },
    {
        "id": "ca12341f.fde6e8",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 640,
        "wires": []
    },
    {
        "id": "fbba11c0.1f358",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 700,
        "wires": []
    },
    {
        "id": "bfddb91d.2b2a98",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 140,
        "wires": []
    },
    {
        "id": "5feebe37.b27b2",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 880,
        "wires": []
    },
    {
        "id": "49be9953.d21e48",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 1140,
        "wires": []
    },
    {
        "id": "22e7b26a.4c54ae",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 740,
        "wires": []
    },
    {
        "id": "ea787f02.584ab",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 1100,
        "wires": []
    },
    {
        "id": "aeea1ecd.3c858",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_7857_HwShuntMetrics",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8('ShuntSocCycles')  \n\t\t.uint32le('RecentTimeAcculmSave') \t// Epoch\n\t\t.uint32le('RecentTimeSocLoRecal') \t// Epoch\n\t\t.uint32le('RecentTimeSocHiRecal') \t// Epoch\n\t\t.uint32le('RecentTimeSocCountLo') \t// Epoch\n\t\t.uint32le('RecentTimeSocCountHi') \t// Epoch\n\t\t.uint8(  'hasShuntSocCountLo') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8(  'hasShuntSocCountHi') \t\t// boolean 0 = Off , 1 = On\n\t\t.int16le('EstDurationToFullmins') \n\t\t.int16le('EstDurationToEmptymins') \n\t\t.floatle('ShuntAcculmAvgCharge',\t{ formatter: (x) => {return x/1000;}})\t// Ah\n\t\t.floatle('ShuntAcculmAvgDischg',\t{ formatter: (x) => {return x/1000;}})\t// Ah\n\t\t.floatle('ShuntAcculmAvgNett',\t\t{ formatter: (x) => {return x/1000;}})\t// Ah\n\t\t.uint32le('ShuntSerialNo') \n\t\t.uint32le('ShuntManuCode') \n\t\t.int16le('ShuntPartNum')\n\t\t.int16le('ShuntVersCode')\n\t\t\n\n  \nmsg.payload = typea.parse(buf);\n\n// convert date(s)\nmsg.payload.RecentTimeAcculmSave = new Date(msg.payload.RecentTimeAcculmSave*1000);\nmsg.payload.RecentTimeSocLoRecal = new Date(msg.payload.RecentTimeSocLoRecal*1000);\nmsg.payload.RecentTimeSocHiRecal = new Date(msg.payload.RecentTimeSocHiRecal*1000);\nmsg.payload.RecentTimeSocCountLo = new Date(msg.payload.RecentTimeSocCountLo*1000);\nmsg.payload.RecentTimeSocCountHi = new Date(msg.payload.RecentTimeSocCountHi*1000);\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 860,
        "y": 840,
        "wires": [
            [
                "90437fe0.fcd83"
            ]
        ]
    },
    {
        "id": "df5c7d37.bd20b",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 840,
        "wires": []
    },
    {
        "id": "7c28d81b.c0dd38",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_3f33_StatusFast",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8('CmuPollerMode') \t    \n\t\t.uint8('CmuTxAckCount')            // Cellmon TX Acknowledgement Count\n\t\t.uint8('CmuTxOpStatusNodeId')      // Cellmon TX Operating Status Node ID\n\t\t.uint8('CmuTxOpStatusUSN')         // Cellmon TX Operating Status Universal Serial Number\n\t\t.uint8('CmuTxOpParamNodeId')       // Cellmon TX Parameter Node ID\n\t\t.int16le('GroupMinCellVolt',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('GroupMaxCellVolt',\t\t{ formatter: (x) => {return x/1000;}})\t\t\n\t\t.uint8('GroupMinCellTemp',\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('GroupMaxCellTemp',\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('CmuRxOpStatusNodeId')\n\t\t.uint8('CmuRxOpStatusGroupAck')\n\t\t.uint8('CmuRxOpStatusUSN')\n\t\t.uint8('CmuRxOpParamNodeId')\n\t\t.uint8('SystemOpStatus') \n\t\t.uint8('SystemAuthMode') \n\t\t.int16le('SupplyVolt',\t\t\t\t{ formatter: (x) => {return x/100;}})\n\t\t.uint8('AmbientTemp',\t\t\t\t{ formatter: (x) => {return x-40;}})   // temperature ºC\n\t\t.uint32le('SystemTime') // Epoch\n\t\t.uint8('ShuntSOC', \t\t\t\t\t{ formatter: (x) => {return x/2-5;}})  // percent\n\t\t.uint8('ShuntTemp',\t\t\t\t\t{ formatter: (x) => {return x-40;}})   // temperature ºC\n\t\t.floatle('NomCapacityToFull',\t\t{ formatter: (x) => {return x/1000;}}) // Ah\n\t\t.floatle('NomCapacityToEmpty',\t\t{ formatter: (x) => {return x/1000;}}) // Ah\n\t\t.uint8('ShuntPollerMode') \n\t\t.uint8('ShuntStatus') /* Choices\n\t\t\t\tIdle Start = 0,\n\t\t\t\tIdle = 1,\n\t\t\t\tSync Start = 2,\n\t\t\t\tSync Running = 3,\n\t\t\t\tNormal = 4,\n\t\t\t\tShuntMon2 SetupStart = 5,\n\t\t\t\tShuntMon2 SetupRunning = 6,\n\t\t\t\tShuntMon2 Normal = 7, */\n\t\t.uint8('hasShuntLoSocRecal')\t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('hasShuntHiSocRecal') \t\t// boolean 0 = Off , 1 = On\n\t\t//  shunt.hasShuntOkSocRange = !(shunt.hasShuntLoSocRecal || shunt.hasShuntHiSocRecal);\n\t\t.uint8('ExpansionOutputFet5') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('ExpansionOutputFet6') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('ExpansionOutputFet7') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('ExpansionOutputFet8') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('ExpansionOutputRelay1') \t// boolean 0 = Off , 1 = On\n\t\t.uint8('ExpansionOutputRelay2') \t// boolean 0 = Off , 1 = On\n\t\t.uint8('ExpansionOutputRelay3') \t// boolean 0 = Off , 1 = On\n\t\t.uint8('ExpansionOutputRelay4') \t// boolean 0 = Off , 1 = On\n\t\t.int16le('ExpansionOutputPwm1') \n\t\t.int16le('ExpansionOutputPwm2') \n\t\t.uint8('ExpansionInput1') \t\t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('ExpansionInput2') \t\t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('ExpansionInput3') \t\t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('ExpansionInput4') \t\t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('ExpansionInput5') \n\t\t.int16le('ExpansionInputAIN1') \n\t\t.int16le('ExpansionInputAIN2') \n\t\t.floatle('MinBypassSession', \t\t{ formatter: (x) => {return x/1000;}}) // Ah\n\t\t.floatle('MaxBypassSession', \t\t{ formatter: (x) => {return x/1000;}}) // Ah\n\t\t.uint8('MinBypassSessionID')\n\t\t.uint8('MaxBypassSessionID')\n\t\t.uint8('RebalanceBypassExtra')  \t// boolean 0 = Off , 1 = On\n\t\t.int16le('RepeatCellVoltCounter') \n\n  \nmsg.payload = typea.parse(buf);\n\n// convert date(s)\nmsg.payload.SystemTime = new Date(msg.payload.SystemTime*1000);\n\n\nswitch(msg.payload.CmuPollerMode) {\n    case 0:\n        msg.payload.CmuPollerMode = \"Idle\";\n        break;\n    case 1:\n        msg.payload.CmuPollerMode = \"Normal\";\n        break;\n    case 2:\n        msg.payload.CmuPollerMode = \" Start collection\";\n        break;\n    case 3:\n        msg.payload.CmuPollerMode = \"Collection running\";\n        break;\n    case 4:\n        msg.payload.CmuPollerMode = \"Start synchronisation\";\n        break;\n    case 5:\n        msg.payload.CmuPollerMode = \"Sync Running\";\n        break;\n    case 6:\n        msg.payload.CmuPollerMode = \"Start NetworkTest\";\n        break;\n    case 7:\n        msg.payload.CmuPollerMode = \"NetworkTest running\";\n        break;\n    case 8:\n        msg.payload.CmuPollerMode = \"Start BypassTest\";\n        break;\n    case 9:\n        msg.payload.CmuPollerMode = \"BypassTest running\";\n        break;\n    case 10:\n        msg.payload.CmuPollerMode = \"Start Reboot All\";\n        break;\n    case 11:\n        msg.payload.CmuPollerMode = \" Reboot All devices\";\n        break;\n    case 12:\n        msg.payload.CmuPollerMode = \" Start Simulator\";\n        break;\n    case 13:\n        msg.payload.CmuPollerMode = \"Simulator running\";\n        break;\n    default:\n        msg.payload.CmuPollerMode = \"Buggered\";\n}\n\nswitch(msg.payload.SystemOpStatus) {\n    case 0:\n        msg.payload.SystemOpStatus = \"Timeout\";\n        break;\n    case 1:\n        msg.payload.SystemOpStatus = \"Idle\";\n        break;\n    case 2:\n        msg.payload.SystemOpStatus = \"Charging\";\n        break;\n    case 3:\n        msg.payload.SystemOpStatus = \"Discharging\";\n        break;\n    case 4:\n        msg.payload.SystemOpStatus = \"Full\";\n        break;\n    case 5:\n        msg.payload.SystemOpStatus = \"Empty\";\n        break;\n    case 6:\n        msg.payload.SystemOpStatus = \"Simulator\";\n        break;\n    case 7:\n        msg.payload.SystemOpStatus = \"CriticalPending\";\n        break;\n    case 8:\n        msg.payload.SystemOpStatus = \"CriticalOffline\";\n        break;\n    case 9:\n        msg.payload.SystemOpStatus = \"MqttOffline\";\n        break;\n    case 10:\n        msg.payload.SystemOpStatus = \"AuthSetup\";\n        break;\n    case 11:\n        msg.payload.SystemOpStatus = \"Shunt Timeout\";\n        break;\n    default:\n        msg.payload.SystemOpStatus = \"Buggered\";\n}\n\nswitch(msg.payload.SystemAuthMode) {\n    case 0:\n        msg.payload.SystemAuthMode = \"Default\";\n        break;\n    case 1:\n        msg.payload.SystemAuthMode = \"Technician\";\n        break;\n    case 2:\n        msg.payload.SystemAuthMode = \"Factory\";\n        break;\n    default:\n        msg.payload.SystemAuthMode = \"Buggered\";\n}\n\nswitch(msg.payload.ShuntPollerMode) {\n    case 0:\n        msg.payload.ShuntPollerMode = \"Idle Start\";\n        break;\n    case 1:\n        msg.payload.ShuntPollerMode = \"Idle\";\n        break;\n    case 2:\n        msg.payload.ShuntPollerMode = \"Sync Start\";\n        break;\n    case 3:\n        msg.payload.ShuntPollerMode = \"Sync Running\";\n        break;\n    case 4:\n        msg.payload.ShuntPollerMode = \"Normal\";\n        break;\n    case 5:\n        msg.payload.ShuntPollerMode = \"ShuntMon2 SetupStart\";\n        break;\n    case 6:\n        msg.payload.ShuntPollerMode = \"ShuntMon2 SetupRunning\";\n        break;\n    case 7:\n        msg.payload.ShuntPollerMode = \"ShuntMon2 Normal\";\n        break;\n    default:\n        msg.payload.ShuntPollerMode = \"Buggered\";\n}\n\nswitch(msg.payload.ShuntStatus) {\n    case 0:\n        msg.payload.ShuntStatus = \"Timeout\";\n        break;\n    case 1:\n        msg.payload.ShuntStatus = \"Discharging\";\n        break;\n    case 2:\n        msg.payload.ShuntStatus = \"Idle\";\n        break;\n    case 4:\n        msg.payload.ShuntStatus = \"Charging\";\n        break;\n    default:\n        msg.payload.ShuntStatus = \"Buggered\";\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 840,
        "y": 640,
        "wires": [
            [
                "ca12341f.fde6e8",
                "8445ce7c.09028",
                "b2ab7d4c.b3ddd",
                "6476769.7ee5988",
                "63dc95b5.2a2dcc",
                "68635fb7.0529d"
            ]
        ]
    },
    {
        "id": "9781b06a.53081",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_415a_CellNodeStatus",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.uint8('ID')\n                .uint8('USN')\n                .int16le('MinCellVolt',                 { formatter: (x) => {return x/1000;}})\n                .int16le('MaxCellVolt',                 { formatter: (x) => {return x/1000;}})\n                .uint8('MinCellTemp',                   { formatter: (x) => {return x-40;}}) // temperature ºC\n                .uint8('BypassTemp',                    { formatter: (x) => {return x-40;}}) // temperature ºC\n                .int16le('BypassAmp',                   { formatter: (x) => {return x/1000;}})\n                .uint8('Status'); /* Choices NodeStatuses\n\t\t\t\t\t\tNone = 0,\n\t\t\t\t\t\tHighVolt = 1,\n\t\t\t\t\t\tHighTemp = 2,\n\t\t\t\t\t\tOk = 3,\n\t\t\t\t\t\tTimeout = 4,\n\t\t\t\t\t\tLowVolt = 5,\n\t\t\t\t\t\tDisabled = 6,\n\t\t\t\t\t\tInBypass = 7,\n\t\t\t\t\t\tInitialBypass = 8,\n\t\t\t\t\t\tFinalBypass = 9,\n\t\t\t\t\t\tMissingSetup = 10,\n\t\t\t\t\t\tNoConfig = 11,\n\t\t\t\t\t\tCellOutLimits = 12, */\n/*\n\t\tvar status = new Packet()\n\t\t.skip(8)\n\t\t.uint8('CmuRxOpStatusNodeID')\n\t\t.uint8('Records')\n\t\t.uint8('FirstNodeID')\n\t\t.uint8('LastNodeID')\n\t\t.array('nodes', {\n\t\t\ttype : Packet(),\n\t\t\tlength : 'Records'\n\t\t})\n*/\n  \nmsg.payload = typea.parse(buf);\n\nswitch(msg.payload.Status) {\n    case 0:\n        msg.payload.Status = \"None\";\n        break;\n    case 1:\n        msg.payload.Status = \"HighVolt\";\n        break;\n    case 2:\n        msg.payload.Status = \"HighTemp\";\n        break;\n    case 3:\n        msg.payload.Status = \"Ok\";\n        break;\n    case 4:\n        msg.payload.Status = \"Timeout\";\n        break;\n    case 5:\n        msg.payload.Status = \"LowVolt\";\n        break;\n    case 6:\n        msg.payload.Status = \"Disabled\";\n        break;\n    case 7:\n        msg.payload.Status = \"InBypass\";\n        break;\n    case 8:\n        msg.payload.Status = \"InitialBypass\";\n        break;\n    case 9:\n        msg.payload.Status = \"FinalBypass\";\n        break;\n    case 10:\n        msg.payload.Status = \"MissingSetup\";\n        break;\n    case 11:\n        msg.payload.Status = \"NoConfig\";\n        break;\n    case 12:\n        msg.payload.Status = \"CellOutLimits\";\n        break;\n    default:\n        msg.payload.Status = \"Buggered\";\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 860,
        "y": 880,
        "wires": [
            [
                "5feebe37.b27b2"
            ]
        ]
    },
    {
        "id": "ad8acc8c.9a174",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 960,
        "wires": []
    },
    {
        "id": "8f7d9f6b.5e7fa",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_3e32_StatusRapid",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.int16le('MinCellVolt',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('MaxCellVolt',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8('MinCellVoltId')\n\t\t.uint8('MaxCellVoltId')\n\t\t.uint8('MinCellTemp',\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('MaxCellTemp',\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('MinCellTempId')\n\t\t.uint8('MaxCellTempId')\n\t\t.int16le('MinBypassAmp', \t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('MaxBypassAmp', \t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8('MinBypassAmpId')\n\t\t.uint8('MaxBypassAmpId')\n\t\t.uint8('MinBypassTemp',\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('MaxBypassTemp',\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('MinBypassTempId',\t{ formatter: (x) => {return x-40;}})\n\t\t.uint8('MaxBypassTempId',\t{ formatter: (x) => {return x-40;}})\n\t\t.int16le('AvgCellVolt',   \t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8('AvgCellTemp',    \t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('NumOfCellsAboveInitialBypass')\n\t\t.uint8('NumOfCellsAboveFinalBypass')\n\t\t.uint8('NumOfCellsInBypass')\n\t\t.uint8('NumOfCellsOverdue')\n\t\t.uint8('NumOfCellsActive')\n\t\t.uint8('NumOfCellsInSystem')\n\t\t.uint8('CmuTxOpStatusId')\n\t\t.uint8('CmuRxOpStatusId')\n\t\t.uint8('CmuRxOpStatusUSN')\n\t\t.int16le('ShuntVoltage',\t{ formatter: (x) => {return x/100;}})  // voltage\n\t\t.floatle('ShuntCurrent',\t{ formatter: (x) => {return x/1000;}}) // amp\n\t\t.floatle('ShuntPowerVA',\t{ formatter: (x) => {return x/1000;}}) // kW \n\n  \nmsg.payload = typea.parse(buf);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 850,
        "y": 140,
        "wires": [
            [
                "bfddb91d.2b2a98",
                "b7222b59.93edf8",
                "76bfaed9.eb6",
                "8fce0a5e.09d718",
                "ab145d35.a525d",
                "739bdfbd.80809"
            ]
        ]
    },
    {
        "id": "86897149.75de7",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_4232_CellNodeFull",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8('ID')\n\t\t.uint8('USN')\n\t\t.int16le('MinCellVolt',\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('MaxCellVolt',\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8('MinCellTemp',\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('BypassTemp',\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.int16le('BypassAmp', \t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8('DataErrorCounter')\n\t\t.uint8('ResetCounter')\n\t\t.uint8('Status') /* Choices NodeStatuses\n\t\t\t\tNone = 0,\n\t\t\t\tHighVolt = 1,\n\t\t\t\tHighTemp = 2,\n\t\t\t\tOk = 3,\n\t\t\t\tTimeout = 4,\n\t\t\t\tLowVolt = 5,\n\t\t\t\tDisabled = 6,\n\t\t\t\tInBypass = 7,\n\t\t\t\tInitialBypass = 8,\n\t\t\t\tFinalBypass = 9,\n\t\t\t\tMissingSetup = 10,\n\t\t\t\tNoConfig = 11,\n\t\t\t\tCellOutLimits = 12, */\t\n\t\t.uint8('IsOverdue')\t\t\t\t// boolean 0 = Off , 1 = On\n\n\t\t.int16le('LoCellVoltAlert',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('HiCellVoltAlert',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('BypassVoltLevel',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('BypassAmpLimit',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8('BypassTempLimit',\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('HiCellTempAlert',\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('RawVoltCalOffset')\n\t\t.int16le('FwVers')\n\t\t.int16le('HwVers')\n\t\t.int16le('BootVers')\n\t\t.uint32le('SerialNo')\t\n\t\t.uint32le('BypassInitialDate') \t// Epoch\n\t\t.floatle('BypassSessionAh',\t\t{ formatter: (x) => {return x/1000;}}) // Ah\n\t\t.uint8('RepeatCellV')\n\n  \nmsg.payload = typea.parse(buf);\n\n// convert date(s)\nmsg.payload.BypassInitialDate = new Date(msg.payload.BypassInitialDate*1000);\n\n\nswitch(msg.payload.Status) {\n    case 0:\n        msg.payload.Status = \"None\";\n        break;\n    case 1:\n        msg.payload.Status = \"HighVolt\";\n        break;\n    case 2:\n        msg.payload.Status = \"HighTemp\";\n        break;\n    case 3:\n        msg.payload.Status = \"Ok\";\n        break;\n    case 4:\n        msg.payload.Status = \"Timeout\";\n        break;\n    case 5:\n        msg.payload.Status = \"LowVolt\";\n        break;\n    case 6:\n        msg.payload.Status = \"Disabled\";\n        break;\n    case 7:\n        msg.payload.Status = \"InBypass\";\n        break;\n    case 8:\n        msg.payload.Status = \"InitialBypass\";\n        break;\n    case 9:\n        msg.payload.Status = \"FinalBypass\";\n        break;\n    case 10:\n        msg.payload.Status = \"MissingSetup\";\n        break;\n    case 11:\n        msg.payload.Status = \"NoConfig\";\n        break;\n    case 12:\n        msg.payload.Status = \"CellOutLimits\";\n        break;\n    default:\n        msg.payload.Status = \"Buggered\";\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 850,
        "y": 920,
        "wires": [
            [
                "ad8acc8c.9a174",
                "b56a71fb.69c95"
            ]
        ]
    },
    {
        "id": "f29277f6.daa798",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 760,
        "wires": []
    },
    {
        "id": "d1133f4a.3ef44",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_4932_ControlRemoteStatus",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8('CanbusRxStatusTicks')  \n\t\t.uint8('CanbusRxUnknownTicks')  \n\t\t.uint8('CanbusTxCmdTicks')  \n\t\t.uint8(  'RemoteChargeActualCelcius', \t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.int16le('RemoteChargeTargetVolt')\n\t\t.int16le('RemoteChargeTargetAmp')\n\t\t.int16le('RemoteChargeTargetVA')\n\t\t.int16le('RemoteChargeActualVolt')\n\t\t.int16le('RemoteChargeActualAmp')\n\t\t.int16le('RemoteChargeActualVA')\n\t\t.uint32le('RemoteChargeActualFlag1')\n\t\t.uint32le('RemoteChargeActualFlag2')\n\t\t.uint32le('RemoteChargeActualRxTime') // Epoch\n\t\t.skip(1)\n\t\t.uint8(  'RemoteDishargeActualCelcius', \t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.int16le('RemoteDischargeTargetVolt')\n\t\t.int16le('RemoteDischargeTargetAmp')\n\t\t.int16le('RemoteDischargeTargetVA')\n\t\t.int16le('RemoteDischargeActualVolt')\n\t\t.int16le('RemoteDischargeActualAmp')\n\t\t.int16le('RemoteDischargeActualVA')\n\t\t.uint32le('RemoteDischargeActualFlag1')\n\t\t.uint32le('RemoteDischargeActualFlag2')\n\t\t.uint32le('RemoteDischargeActualRxTime') // Epoch\n  \nmsg.payload = typea.parse(buf);\n\n// convert date(s)\nmsg.payload.RemoteChargeActualRxTime = new Date(msg.payload.RemoteChargeActualRxTime*1000);\nmsg.payload.RemoteDischargeActualRxTime = new Date(msg.payload.RemoteDischargeActualRxTime*1000);\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 880,
        "y": 760,
        "wires": [
            [
                "f29277f6.daa798"
            ]
        ]
    },
    {
        "id": "10983267.223e1e",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 800,
        "wires": []
    },
    {
        "id": "d2fa3827.0fb158",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_6131_StatusComms",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint32le('SystemTime') // Epoch\n\t\t.uint8('SystemOpStatus') /* Choices\n\t\t\t\tSimulator = 0,   \t  // LED = rainbow pulse\n\t\t\t\tIdle = 1,        \t  // LED = green slow pulse\n\t\t\t\tDischarging = 2, \t  // LED = green solid \n\t\t\t\tSoC Empty = 3,   \t  // LED = green double blink\n\t\t\t\tCharging = 4,    \t  // LED = blue slow pulse\n\t\t\t\tFull = 5,        \t  // LED = blue double blink\n\t\t\t\tTimeout = 6,     \t  // LED = red solid\n\t\t\t\tCritical Pending = 7, // LED = red fast pulse\n\t\t\t\tCritical Offline = 8, // LED = red slow pulse\n\t\t\t\tMqtt Offline = 9,     // LED = white blink\n\t\t\t\tAuth Setup = 10,      // LED = white solid\n\t\t\t\tShunt Timeout = 11,   // LED = red solid  \t*/\n\t\t.uint8('SystemAuthMode') /* Choices\n\t\t\t\tDefault = 0,\n\t\t\t\tTechnician = 1,\n\t\t\t\tFactory = 2, */\n\t\t.int16le('SystemAuthToken')\n\t\t.int16le('SystemAuthRejectTicks')\n\t\t.uint8('WifiState') /* Choices WifiOpStates\n\t\t\t\tBroadcast Start = 0,\n\t\t\t\tBroadcast Prep = 1,\n\t\t\t\tBroadcast TxSetup = 2,\n\t\t\t\tBroadcast Running = 3,\n\t\t\t\tUsbCmd Start = 4,\n\t\t\t\tUsbCmd Running = 5,\n\t\t\t\tUsbCmd PassThru = 6,\n\t\t\t\tUsbProg Start = 7,\n\t\t\t\tUsbProg Running = 8,\n\t\t\t\tUsbProg PassThru = 9,\n\t\t\t\tOffline Start = 10,\n\t\t\t\tOffline Running = 11,\n\t\t\t\tOffline Stop = 12,\n\t\t\t\tLimited Start = 13,\n\t\t\t\tLimited Prep = 14,\n\t\t\t\tLimited Running = 15,\n\t\t\t\tJoinAp Start = 16,\n\t\t\t\tJoinAp Running = 17,\t*/\t\t\n\t\t.uint8('WifiTxCmdTicks') \n\t\t.uint8('WifiRxCmdTicks') \n\t\t.uint8('WifiRxUnknownTicks') \n\t\t.uint8('CanbusOpStatus') /* Choices \n\t\t\t\t\n\t\t\t\t \t*/\t\t\n\t\t.uint8('CanbusRxStatusTicks')\n\t\t.uint8('CanbusRxUnknownTicks')\n\t\t.uint8('CanbusRxStatusTicks')\n\t\t.uint8('ShuntPollerMode') /* Choices ShuntPollerModes\n\t\t\t\tIdle Start = 0,\n\t\t\t\tIdle = 1,\n\t\t\t\tSync Start = 2,\n\t\t\t\tSync Running = 3,\n\t\t\t\tNormal = 4,\n\t\t\t\tShuntMon2 SetupStart = 5,\n\t\t\t\tShuntMon2 SetupRunning = 6,\n\t\t\t\tShuntMon2 Normal = 7, */\n\t\t.uint8('ShuntStatus') /* Choices  ShuntStatuses\n\t\t\t\tTimeout = 0,\n\t\t\t\tDischarging = 1,\n\t\t\t\tIdle = 2,\n\t\t\t\tCharging = 4 */\n\t\t.uint8('ShuntRxAmpTicks')\n\t\t.uint8('ShuntTxAmpTicks')\n\t\t.uint8('CmuPollerMode') \t    /* Choices\n\t\t\t\tIdle = 0,\n\t\t\t\tNormal = 1,\n\t\t\t\tCollection Start = 2,\n\t\t\t\tCollection Running = 3,\n\t\t\t\tSync Start = 4,\n\t\t\t\tSync Running = 5,\n\t\t\t\tNetworkTest Start = 6,\n\t\t\t\tNetworkTest Running = 9,\n\t\t\t\tBypassTest Start = 7,\n\t\t\t\tBypassTest Running = 8,\n\t\t\t\tRebootAll Start = 10,\n\t\t\t\tRebooting AllDevices = 11,\n\t\t\t\tSimulator Start = 12,\n\t\t\t\tSimulator Running = 13, */\n\t\t.uint8('CmuOpStatus') /* Choices */\n\t\t.uint8('CmuTxCmdTicks')\n\t\t\nmsg.payload = typea.parse(buf);\n\n\n// convert date(s)\nmsg.payload.SystemTime = new Date(msg.payload.SystemTime*1000);\n\nswitch(msg.payload.SystemOpStatus) {\n    case 0:\n        msg.payload.SystemOpStatus = \"Simulator\";\n        break;\n    case 1:\n        msg.payload.SystemOpStatus = \"Idle\";\n        break;\n    case 2:\n        msg.payload.SystemOpStatus = \"Discharging\";\n        break;\n    case 3:\n        msg.payload.SystemOpStatus = \"SoC Empty\";\n        break;\n    case 4:\n        msg.payload.SystemOpStatus = \"Charging\";\n        break;\n    case 5:\n        msg.payload.SystemOpStatus = \"Full\";\n        break;\n    case 6:\n        msg.payload.SystemOpStatus = \"Timeout\";\n        break;\n    case 7:\n        msg.payload.SystemOpStatus = \"Critical Pending\";\n        break;\n    case 8:\n        msg.payload.SystemOpStatus = \"Critical Offline\";\n        break;\n    case 9:\n        msg.payload.SystemOpStatus = \"Mqtt Offline\";\n        break;\n    case 10:\n        msg.payload.SystemOpStatus = \"Auth Setup\";\n        break;\n    case 11:\n        msg.payload.SystemOpStatus = \"Shunt Timeout\";\n        break;\n    default:\n        msg.payload.SystemOpStatus = \"Buggered\";\n}\n\nswitch(msg.payload.SystemAuthMode) {\n    case 0:\n        msg.payload.SystemAuthMode = \"Default\";\n        break;\n    case 1:\n        msg.payload.SystemAuthMode = \"Technician\";\n        break;\n    case 2:\n        msg.payload.SystemAuthMode = \"Factory\";\n        break;\n    default:\n        msg.payload.SystemAuthMode = \"Buggered\";\n}\n\nswitch(msg.payload.WifiState) {\n    case 0:\n        msg.payload.WifiState = \"Broadcast Start\";\n        break;\n    case 1:\n        msg.payload.WifiState = \"Broadcast Prep\";\n        break;\n    case 2:\n        msg.payload.WifiState = \"Broadcast TxSetup\";\n        break;\n    case 3:\n        msg.payload.WifiState = \"Broadcast Running\";\n        break;\n    case 4:\n        msg.payload.WifiState = \"UsbCmd Start\";\n        break;\n    case 5:\n        msg.payload.WifiState = \"UsbCmd Running\";\n        break;\n    case 6:\n        msg.payload.WifiState = \"UsbCmd PassThru\";\n        break;\n    case 7:\n        msg.payload.WifiState = \"UsbProg Start\";\n        break;\n    case 8:\n        msg.payload.WifiState = \"UsbProg Running\";\n        break;\n    case 9:\n        msg.payload.WifiState = \"UsbProg PassThru\";\n        break;\n    case 10:\n        msg.payload.WifiState = \"Offline Start\";\n        break;\n    case 11:\n        msg.payload.WifiState = \"Offline Running\";\n        break;\n    case 12:\n        msg.payload.WifiState = \"Offline Stop\";\n        break;\n    case 13:\n        msg.payload.WifiState = \"Limited Start\";\n        break;\n    case 14:\n        msg.payload.WifiState = \"Limited Prep\";\n        break;\n    case 15:\n        msg.payload.WifiState = \"Limited Running\";\n        break;\n    case 16:\n        msg.payload.WifiState = \"JoinAp Start\";\n        break;\n    case 17:\n        msg.payload.WifiState = \"JoinAp Running\";\n        break;\n    default:\n        msg.payload.WifiState = \"Buggered\";\n}\n\nswitch(msg.payload.ShuntPollerMode) {\n    case 0:\n        msg.payload.ShuntPollerMode = \"Idle Start\";\n        break;\n    case 1:\n        msg.payload.ShuntPollerMode = \"Idle\";\n        break;\n    case 2:\n        msg.payload.ShuntPollerMode = \"Sync Start\";\n        break;\n    case 3:\n        msg.payload.ShuntPollerMode = \"Sync Running\";\n        break;\n    case 4:\n        msg.payload.ShuntPollerMode = \"Normal\";\n        break;\n    case 5:\n        msg.payload.ShuntPollerMode = \"ShuntMon2 SetupStart\";\n        break;\n    case 6:\n        msg.payload.ShuntPollerMode = \"ShuntMon2 SetupRunning\";\n        break;\n    case 7:\n        msg.payload.ShuntPollerMode = \"ShuntMon2 Normal\";\n        break;\n    default:\n        msg.payload.ShuntPollerMode = \"Buggered\";\n}\n\nswitch(msg.payload.ShuntStatus) {\n    case 0:\n        msg.payload.ShuntStatus = \"Timeout\";\n        break;\n    case 1:\n        msg.payload.ShuntStatus = \"Discharging\";\n        break;\n    case 2:\n        msg.payload.ShuntStatus = \"Idle\";\n        break;\n    case 4:\n        msg.payload.ShuntStatus = \"Charging\";\n        break;\n    default:\n        msg.payload.ShuntStatus = \"Buggered\";\n}\n\nswitch(msg.payload.CmuPollerMode) {\n    case 0:\n        msg.payload.CmuPollerMode = \"Idle\";\n        break;\n    case 1:\n        msg.payload.CmuPollerMode = \"Normal\";\n        break;\n    case 2:\n        msg.payload.CmuPollerMode = \"Collection Start\";\n        break;\n    case 3:\n        msg.payload.CmuPollerMode = \"Collection Running\";\n        break;\n    case 4:\n        msg.payload.CmuPollerMode = \"Sync Start\";\n        break;\n    case 5:\n        msg.payload.CmuPollerMode = \"Sync Running\";\n        break;\n    case 6:\n        msg.payload.CmuPollerMode = \"NetworkTest Start\";\n        break;\n    case 7:\n        msg.payload.CmuPollerMode = \"NetworkTest Running\";\n        break;\n    case 8:\n        msg.payload.CmuPollerMode = \"BypassTest Start\";\n        break;\n    case 9:\n        msg.payload.CmuPollerMode = \"BypassTest Running\";\n        break;\n    case 10:\n        msg.payload.CmuPollerMode = \"RebootAll Start\";\n        break;\n    case 11:\n        msg.payload.CmuPollerMode = \"Rebooting AllDevices\";\n        break;\n    case 12:\n        msg.payload.CmuPollerMode = \"Simulator Start\";\n        break;\n    case 13:\n        msg.payload.CmuPollerMode = \"Simulator Running\";\n        break;\n    default:\n        msg.payload.CmuPollerMode = \"Buggered\";\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 850,
        "y": 800,
        "wires": [
            [
                "10983267.223e1e"
            ]
        ]
    },
    {
        "id": "3b6043f2.c8f11c",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 380,
        "wires": []
    },
    {
        "id": "40d3fdc.2a54504",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "Msg_5732_SystemDiscovery",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.string('SystemCode', \t{ encoding: 'ascii', length: 8 })\n\t\t.int16le('SystemFirmwareVersion')\n\t\t.int16le('SystemHardwareVersion')\n\t\t.int32le('SystemTime') // Epoch\n\t\t.uint8('SystemOpStatus') /* Choices\n\t\t\t\tSimulator = 0,   \t  // LED = rainbow pulse\n\t\t\t\tIdle = 1,        \t  // LED = green slow pulse\n\t\t\t\tDischarging = 2, \t  // LED = green solid \n\t\t\t\tSoC Empty = 3,   \t  // LED = green double blink\n\t\t\t\tCharging = 4,    \t  // LED = blue slow pulse\n\t\t\t\tFull = 5,        \t  // LED = blue double blink\n\t\t\t\tTimeout = 6,     \t  // LED = red solid\n\t\t\t\tCritical Pending = 7, // LED = red fast pulse\n\t\t\t\tCritical Offline = 8, // LED = red slow pulse\n\t\t\t\tMqtt Offline = 9,     // LED = white blink\n\t\t\t\tAuth Setup = 10,      // LED = white solid\n\t\t\t\tShunt Timeout = 11,   // LED = red solid  \t*/\n\t\t.uint8('SystemAuthMode') /* Choices\n\t\t\t\tDefault \t= 0,\n\t\t\t\tTechnician \t= 1,\n\t\t\t\tFactory \t= 2, */\n\t\t.uint8('CriticalBatOkState')    // 0 = Off , 1 = On\n\t\t.uint8('ChargePowerRateState')  /* Choices\n\t\t\t\tOff \t\t\t= 0,\n\t\t\t\tLimited Power \t= 2,\n\t\t\t\tNormal Power  \t= 4, */\n\t\t.uint8('DischargePowerRateState') /* Choices\n\t\t\t\tOff \t\t\t= 0,\n\t\t\t\tLimited Power \t= 2,\n\t\t\t\tNormal Power  \t= 4, */\n\t\t.uint8('HeatOnState') \t\t\t// 0 = Off , 1 = On\n\t\t.uint8('CoolOnState') \t\t\t// 0 = Off , 1 = On\n\t\t.int16le('MinCellVolt', \t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('MaxCellVolt', \t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('AvgCellVolt', \t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8('MinCellTemp', \t\t{ formatter: (x) => {return x-40;}})     // temperature ºC\n\t\t.uint8('NumOfCellsActive')\n\t\t.uint8('CmuRxOpStatusUSN')\n\t\t.uint8('CmuPollerMode')  /* Choices\n\t\t\t\tIdle = 0,\n\t\t\t\tNormal = 1,\n\t\t\t\tCollection Start = 2,\n\t\t\t\tCollection Running = 3,\n\t\t\t\tSync Start = 4,\n\t\t\t\tSync Running = 5,\n\t\t\t\tNetworkTest Start = 6,\n\t\t\t\tNetworkTest Running = 9,\n\t\t\t\tBypassTest Start = 7,\n\t\t\t\tBypassTest Running = 8,\n\t\t\t\tRebootAll Start = 10,\n\t\t\t\tRebooting AllDevices = 11,\n\t\t\t\tSimulator Start = 12,\n\t\t\t\tSimulator Running = 13, */\n\t\t.uint8('ShuntSOC',\t\t\t{ formatter: (x) => {return x/2-5;}})    // percent\n\t\t.int16le('ShuntVoltage',\t{ formatter: (x) => {return x/100;}})\n\t\t.floatle('ShuntCurrent',\t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8('ShuntStatus') /* Choices\n\t\t\t\tTimeout = 0,\n\t\t\t\tDischarging = 1,\n\t\t\t\tIdle = 2,\n\t\t\t\tCharging = 4 */\n\t\t.uint8('ShuntRxAmpTicks')\n  \nmsg.payload = typea.parse(buf);\n\n// convert date(s)\nmsg.payload.SystemTime = new Date(msg.payload.SystemTime*1000);\n\nswitch(msg.payload.SystemOpStatus) {\n    case 0:\n        msg.payload.SystemOpStatus = \"Timeout\";\n        break;\n    case 1:\n        msg.payload.SystemOpStatus = \"Idle\";\n        break;\n    case 2:\n        msg.payload.SystemOpStatus = \"Charging\";\n        break;\n    case 3:\n        msg.payload.SystemOpStatus = \"Discharging\";\n        break;\n    case 4:\n        msg.payload.SystemOpStatus = \"Full\";\n        break;\n    case 5:\n        msg.payload.SystemOpStatus = \"Empty\";\n        break;\n    case 6:\n        msg.payload.SystemOpStatus = \"Simulator\";\n        break;\n    case 7:\n        msg.payload.SystemOpStatus = \"CriticalPending\";\n        break;\n    case 8:\n        msg.payload.SystemOpStatus = \"CriticalOffline\";\n        break;\n    case 9:\n        msg.payload.SystemOpStatus = \"MqttOffline\";\n        break;\n    case 10:\n        msg.payload.SystemOpStatus = \"AuthSetup\";\n        break;\n    case 11:\n        msg.payload.SystemOpStatus = \"Shunt Timeout\";\n        break;\n    default:\n        msg.payload.SystemOpStatus = \"Buggered\";\n}\n\nswitch(msg.payload.SystemAuthMode) {\n    case 0:\n        msg.payload.SystemAuthMode = \"Default\";\n        break;\n    case 1:\n        msg.payload.SystemAuthMode = \"Technician\";\n        break;\n    case 2:\n        msg.payload.SystemAuthMode = \"Factory\";\n        break;\n    default:\n        msg.payload.SystemAuthMode = \"Buggered\";\n}\n\nswitch(msg.payload.ChargePowerRateState) {\n    case 0:\n        msg.payload.ChargePowerRateState = \"Off\";\n        break;\n    case 2:\n        msg.payload.ChargePowerRateState = \"Limited Power\";\n        break;\n    case 4:\n        msg.payload.ChargePowerRateState = \"Normal Power\";\n        break;\n    default:\n        msg.payload.ChargePowerRateState = \"Buggered\";\n}\n\nswitch(msg.payload.DischargePowerRateState) {\n    case 0:\n        msg.payload.DischargePowerRateState = \"Off\";\n        break;\n    case 2:\n        msg.payload.DischargePowerRateState = \"Limited Power\";\n        break;\n    case 4:\n        msg.payload.DischargePowerRateState = \"Normal Power\";\n        break;\n    default:\n        msg.payload.DischargePowerRateState = \"Buggered\";\n}\n\nswitch(msg.payload.CmuPollerMode) {\n    case 0:\n        msg.payload.CmuPollerMode = \"Idle\";\n        break;\n    case 1:\n        msg.payload.CmuPollerMode = \"Normal\";\n        break;\n    case 2:\n        msg.payload.CmuPollerMode = \" Start collection\";\n        break;\n    case 3:\n        msg.payload.CmuPollerMode = \"Collection running\";\n        break;\n    case 4:\n        msg.payload.CmuPollerMode = \"Start synchronisation\";\n        break;\n    case 5:\n        msg.payload.CmuPollerMode = \"Sync Running\";\n        break;\n    case 6:\n        msg.payload.CmuPollerMode = \"Start NetworkTest\";\n        break;\n    case 7:\n        msg.payload.CmuPollerMode = \"NetworkTest running\";\n        break;\n    case 8:\n        msg.payload.CmuPollerMode = \"Start BypassTest\";\n        break;\n    case 9:\n        msg.payload.CmuPollerMode = \"BypassTest running\";\n        break;\n    case 10:\n        msg.payload.CmuPollerMode = \"Start Reboot All\";\n        break;\n    case 11:\n        msg.payload.CmuPollerMode = \" Reboot All devices\";\n        break;\n    case 12:\n        msg.payload.CmuPollerMode = \" Start Simulator\";\n        break;\n    case 13:\n        msg.payload.CmuPollerMode = \"Simulator running\";\n        break;\n    default:\n        msg.payload.CmuPollerMode = \"Buggered\";\n}\n\nswitch(msg.payload.ShuntStatus) {\n    case 0:\n        msg.payload.ShuntStatus = \"Timeout\";\n        break;\n    case 1:\n        msg.payload.ShuntStatus = \"Discharging\";\n        break;\n    case 2:\n        msg.payload.ShuntStatus = \"Idle\";\n        break;\n    case 4:\n        msg.payload.ShuntStatus = \"Charging\";\n        break;\n    default:\n        msg.payload.ShuntStatus = \"Buggered\";\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 860,
        "y": 380,
        "wires": [
            [
                "3b6043f2.c8f11c"
            ]
        ]
    },
    {
        "id": "e321fbb8.b60e48",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 420,
        "wires": []
    },
    {
        "id": "6ba51319.a7a48c",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_4032_StatusSlow",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n \t\t.skip(8)\n\t\t.uint32le('SystemTime') \t\t\t// Epoch\n\t\t.uint8('IsProcessControl') \t\t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('IsInitialStartup') \t\t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('IgnoreWhenCellsOverdue') \t// boolean 0 = Off , 1 = On\n\t\t.uint8('IgnoreWhenShuntsOverdue') \t// boolean 0 = Off , 1 = On\n\t\t.uint8('MonitorDailySessionStats') \t// boolean 0 = Off , 1 = On\t\t\n\t\t.uint8('HwSystemSetupVers') \n\t\t.uint8('HwCellmonSetupVers') \n\t\t.uint8('HwShuntSetupVers') \n\t\t.uint8('HwExpansionSetupVers') \n\t\t.uint8('HwIntegrationSetupVers') \n\t\t.uint8('ControlCriticalSetupVers') \n\t\t.uint8('ControlChargeSetupVers')  \n\t\t.uint8('ControlDischargeSetupVers')  \t\t\n\t\t.uint8('ControlThermalSetupVers')  \n\t\t.uint8('ControlRemoteSetupVers')  \n\t\t.uint8('ControlSchedulerSetupVers') \t\t\t\n\t\t.int16le('EstDurationToFullmins') \n\t\t.int16le('EstDurationToEmptymins') \n\t\t.floatle('ShuntAcculmAvgCharge',\t{ formatter: (x) => {return x/1000;}}) // Ah\n\t\t.floatle('ShuntAcculmAvgDischg',\t{ formatter: (x) => {return x/1000;}}) // Ah\n\t\t.floatle('ShuntAcculmAvgNett',\t\t{ formatter: (x) => {return x/1000;}}) // Ah\n\t\t.uint8(  'hasShuntSocCountLo') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8(  'hasShuntSocCountHi') \t\t// boolean 0 = Off , 1 = On\t\t\n\t\t.uint32le('QuickSessRecentTime') \t// EPOCH\n\t\t.int16le('QuickSessNumOfRecords')\n\t\t.int16le('QuickSessMaxNumOfRecords')\n\t\t.skip(8) // acculmNett ADC counter \n\t\t.floatle('NomCapacityToEmpty',\t\t{ formatter: (x) => {return x/1000;}}) // Ah\n\t\t\nmsg.payload = typea.parse(buf);\n// convert date(s)\nmsg.payload.SystemTime = new Date(msg.payload.SystemTime*1000);\nmsg.payload.QuickSessRecentTime = new Date(msg.payload.QuickSessRecentTime*1000);\n\n\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 840,
        "y": 420,
        "wires": [
            [
                "e321fbb8.b60e48",
                "9a44bb7a.474bd8"
            ]
        ]
    },
    {
        "id": "9a3c0c25.d705a",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 500,
        "wires": []
    },
    {
        "id": "1704d7ce.245b58",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_5432_DailySession",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.int16le('DailySessionMinCellVolt',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('DailySessionMaxCellVolt',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('DailySessionMinSupplyVolt',\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('DailySessionMaxSupplyVolt',\t{ formatter: (x) => {return x/100;}})\n\t\t.uint8('DailySessionMinReportTemp',\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('DailySessionMaxReportTemp',\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.int16le('DailySessionMinShuntVolt',\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('DailySessionMaxShuntVolt',\t{ formatter: (x) => {return x/100;}})\n\t\t.uint8('DailySessionMinShuntSoc', \t\t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.uint8('DailySessionMaxShuntSoc', \t\t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.uint8('DailySessionThermalBandA',\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionThermalBandB',\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionThermalBandC',\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionThermalBandD',\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionThermalBandE',\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionThermalBandF',\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionThermalBandG',\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionThermalBandH',\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionSocBandA',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionSocBandB',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionSocBandC',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionSocBandD',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionSocBandE',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionSocBandF',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionSocBandG',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionSocBandH',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.int16le('DailySessionShuntPeakCharge',{ formatter: (x) => {return x/100;}}) // amps\n\t\t.int16le('DailySessionShuntPeakDischg',{ formatter: (x) => {return x/100;}}) // amps\n\t\t.uint8('DailySessionCriticalEvents')\n\t\t.int32le('DailySessionStartTime') \t// Epoch\n\t\t.int32le('DailySessionFinishTime')  // Epoch\n\t\t.floatle('DailySessionCumulShuntAhCharge',{ formatter: (x) => {return x/1000;}})  // Ah\n\t\t.floatle('DailySessionCumulShuntAhDischg',{ formatter: (x) => {return x/1000;}})  // Ah\n\t\t.floatle('DailySessionCumulShuntkWhCharge',{ formatter: (x) => {return x/1000;}}) // kWh\n\t\t.floatle('DailySessionCumulShuntkWhDischg',{ formatter: (x) => {return x/1000;}}) // kWh\n\t\t\n  \nmsg.payload = typea.parse(buf);\n\n// convert date(s)\nmsg.payload.DailySessionStartTime = new Date(msg.payload.DailySessionStartTime*1000);\nmsg.payload.DailySessionFinishTime = new Date(msg.payload.DailySessionFinishTime*1000);\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 850,
        "y": 500,
        "wires": [
            [
                "9a3c0c25.d705a",
                "684ac7ee.c50fc8",
                "7e92a896.171e58"
            ]
        ]
    },
    {
        "id": "122c8b3f.160005",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_5632_LifetimeMetrics",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint32le('FirstSyncTime') \t\t\t// Epoch\n\t\t.uint32le('LifeCountStartup') \n\t\t.uint32le('LifeCountCriticalBattOk') \n\t\t.uint32le('LifeCountChargeOn') \n\t\t.uint32le('LifeCountChargeLimp') \n\t\t.uint32le('LifeCountDischgOn') \n\t\t.uint32le('LifeCountDischgLimp') \n\t\t.uint32le('LifeCountHeatOn') \n\t\t.uint32le('LifeCountCoolOn') \n\t\t.int16le( 'LifeCountDailySession') \n\t\t.uint32le('RecentTimeCriticalOn') \t// Epoch\n\t\t.uint32le('RecentTimeCriticalOff') \t// Epoch\n\t\t.uint32le('RecentTimeChargeOn') \t// Epoch\n\t\t.uint32le('RecentTimeChargeOff') \t// Epoch\n\t\t.uint32le('RecentTimeChargeLimp') \t// Epoch\n\t\t.uint32le('RecentTimeDischgOn') \t// Epoch\n\t\t.uint32le('RecentTimeDischgOff') \t// Epoch\n\t\t.uint32le('RecentTimeDischgLimp') \t// Epoch\n\t\t.uint32le('RecentTimeHeatOn') \t\t// Epoch\n\t\t.uint32le('RecentTimeHeatOff') \t\t// Epoch\n\t\t.uint32le('RecentTimeCoolOn') \t\t// Epoch\n\t\t.uint32le('RecentTimeCoolOff') \t\t// Epoch\n\t\t.uint32le('RecentTimeBypassInitial') // Epoch\n\t\t.uint32le('RecentTimeBypassComplete') // Epoch\n\t\t.uint32le('RecentTimeBypassTest') \t// Epoch\n\t\t.uint8('SystemBypassTestOutcome')  /* Choices BypassTestOutcomes\n\t\t\tNotTested = 0,\n\t\t\tPreparing = 1,\n\t\t\tTesting = 2,\n\t\t\tPassOk = 3,\n\t\t\tFailed = 4, */\n\t\t.uint32le('RecentTimeWizardSetup') // Epoch\n\t\t.uint32le('RecentTimeBypassExtra') // Epoch\n\n  \nmsg.payload = typea.parse(buf);\n\n// convert date(s)\nmsg.payload.FirstSyncTime = new Date(msg.payload.FirstSyncTime*1000);\nmsg.payload.RecentTimeCriticalOn = new Date(msg.payload.RecentTimeCriticalOn*1000);\nmsg.payload.RecentTimeCriticalOff = new Date(msg.payload.RecentTimeCriticalOff*1000);\nmsg.payload.RecentTimeChargeOn = new Date(msg.payload.RecentTimeChargeOn*1000);\nmsg.payload.RecentTimeChargeOff = new Date(msg.payload.RecentTimeChargeOff*1000);\nmsg.payload.RecentTimeChargeLimp = new Date(msg.payload.RecentTimeChargeLimp*1000);\nmsg.payload.RecentTimeDischgOn = new Date(msg.payload.RecentTimeDischgOn*1000);\nmsg.payload.RecentTimeDischgOff = new Date(msg.payload.RecentTimeDischgOff*1000);\nmsg.payload.RecentTimeDischgLimp = new Date(msg.payload.RecentTimeDischgLimp*1000);\nmsg.payload.RecentTimeHeatOn = new Date(msg.payload.RecentTimeHeatOn*1000);\nmsg.payload.RecentTimeHeatOff = new Date(msg.payload.RecentTimeHeatOff*1000);\nmsg.payload.RecentTimeCoolOn = new Date(msg.payload.RecentTimeCoolOn*1000);\nmsg.payload.RecentTimeCoolOff = new Date(msg.payload.RecentTimeCoolOff*1000);\nmsg.payload.RecentTimeBypassInitial = new Date(msg.payload.RecentTimeBypassInitial*1000);\nmsg.payload.RecentTimeBypassComplete = new Date(msg.payload.RecentTimeBypassComplete*1000);\nmsg.payload.RecentTimeBypassTest = new Date(msg.payload.RecentTimeBypassTest*1000);\nmsg.payload.RecentTimeWizardSetup = new Date(msg.payload.RecentTimeWizardSetup*1000);\nmsg.payload.RecentTimeBypassExtra = new Date(msg.payload.RecentTimeBypassExtra*1000);\n\nswitch(msg.payload.SystemBypassTestOutcome) {\n    case 0:\n        msg.payload.SystemBypassTestOutcome = \"NotTested\";\n        break;\n    case 1:\n        msg.payload.SystemBypassTestOutcome = \"Preparing\";\n        break;\n    case 2:\n        msg.payload.SystemBypassTestOutcome = \"Testing\";\n        break;\n    case 3:\n        msg.payload.SystemBypassTestOutcome = \"PassOk\";\n        break;\n    case 4:\n        msg.payload.SystemBypassTestOutcome = \"Failed\";\n        break;\n    default:\n        msg.payload.SystemBypassTestOutcome = \"Buggered\";\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 120,
        "y": 620,
        "wires": [
            [
                "dbbeb1bd.5221"
            ]
        ]
    },
    {
        "id": "dbbeb1bd.5221",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 390,
        "y": 620,
        "wires": []
    },
    {
        "id": "bc35aeeb.93ab7",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "Msg_4a35_HwSystemSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.int16le('HwSystemSetupVers')\n\t\t.string('SystemCode', \t{ encoding: 'ascii', length: 8 })\n\t\t.string('SysName', \t\t{ encoding: 'ascii', length: 20 })\n\t\t.string('AssetCode', \t{ encoding: 'ascii', length: 20 })\n\t\t.uint8('AllowTechAuth') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('AllowQuickSession') \t// boolean 0 = Off , 1 = On\n\t\t.uint32le('QuickSessionInterval', { formatter: (x) => {return x/1000;}})  // seconds\n\t\t.int16le('SystemPresetId')\n\t\t.int16le('SystemFirmwareVersion')\n\t\t.int16le('SystemHardwareVersion')\n\t\t.uint32le('SystemSerialNo')\n\t\t.uint8('ShowScheduler') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('ShowStripCycle') \t\t// boolean 0 = Off , 1 = On\n\t\t\nmsg.payload = typea.parse(buf);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 120,
        "y": 660,
        "wires": [
            [
                "ecea2916.d52128"
            ]
        ]
    },
    {
        "id": "ecea2916.d52128",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 660,
        "wires": []
    },
    {
        "id": "a7cdb5ee.7c66c8",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_4d33_HwExpansionSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8('HwExpansionSetupVers')  \n\t\t.uint8('HwExpansionTemplate')  /* ExtensionTemplateOptions\n\t\t\t\tNone = 0,\n\t\t\t\tExpansionBoard 12v = 1,\n\t\t\t\tExpansionBoard 48v = 2,\n\t\t\t\tWatchMonCmC v2.0   = 3,\t*/\t\n\t\t.uint8('HwExpansionNeoPixelMode')  /* NeoPixelExtStatusModes\n\t\t\t\tNone \t\t\t\t= 0,\n\t\t\t\tRepeat \t\t\t\t= 1,\n\t\t\t\tStatus + 7seg SoC% \t= 2,\n\t\t\t\tSolid SoC% 8seg \t= 3,\t*/\n\t\t.uint8('HwExpansionRelay1')  /* ExpansionOutputAssignments\n\t\t\t\tNone = 0,\n\t\t\t\tManualOn = 1,\n\t\t\t\tCritical BattOk = 2,\n\t\t\t\tCharging On = 4,\n\t\t\t\tDischarging On = 5,\n\t\t\t\tHeating Required = 6,\n\t\t\t\tCooling Required = 7,\n\t\t\t\tRun / Idle input = 8,\n\t\t\t\tCharge / Normal input = 9,\n\t\t\t\tBypass Complete = 10,\n\t\t\t\tCharging Limited = 11,\n\t\t\t\tDischarging Limited = 12,\n\t\t\t\tCritical Recovery = 13,\n\t\t\t\tCritical PulseOn = 14,\n\t\t\t\tCritical PulseOff = 15,\n\t\t\t\tCritical Fault = 16,\n\t\t\t\tCritical PrechargeTimer = 17, */\n\t\t.uint8('HwExpansionRelay2')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionRelay3')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionRelay4')\t\t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput5')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput5')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput7')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput8')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput9')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput10') \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionInput1')  \t/* ExtensionInputOptions\n\t\t\t\tNone \t\t\t\t\t= 0,\n\t\t\t\tRun / Idle mode \t\t= 1,\n\t\t\t\tCharge / Normal mode \t= 2,\n\t\t\t\tCritical contact sensor - On = 3,\n\t\t\t\tCritical contact sensor - Fault = 4, */\n\t\t.uint8('HwExpansionInput2')  \t/* ExtensionInputOptions */\n\t\t.uint8('HwExpansionInput3')  \t/* ExtensionInputOptions */\n\t\t.uint8('HwExpansionInput4')  \t/* ExtensionInputOptions */\n\t\t.uint8('HwExpansionInput5')  \t/* ExtensionInputOptions */\n\t\t.uint8('HwExpansionInputAIN1') \n\t\t.uint8('HwExpansionInputAIN2') \n\t\t.int16le('HwExpansionCustomFeature1')\n\t\t.int16le('HwExpansionCustomFeature2')\n\n  \nmsg.payload = typea.parse(buf);\n\n\nswitch(msg.payload.HwExpansionTemplate) {\n    case 0:\n        msg.payload.HwExpansionTemplate = \"None\";\n        break;\n    case 1:\n        msg.payload.HwExpansionTemplate = \"ExpansionBoard 12v\";\n        break;\n    case 2:\n        msg.payload.HwExpansionTemplate = \"ExpansionBoard 48v\";\n        break;\n    case 3:\n        msg.payload.HwExpansionTemplate = \"WatchMonCmC v2.0\";\n        break;\n    default:\n        msg.payload.HwExpansionTemplate = \"Buggered\";\n}\n\nswitch(msg.payload.HwExpansionNeoPixelMode) {\n    case 0:\n        msg.payload.HwExpansionNeoPixelMode = \"None\";\n        break;\n    case 1:\n        msg.payload.HwExpansionNeoPixelMode = \"Repeat\";\n        break;\n    case 2:\n        msg.payload.HwExpansionNeoPixelMode = \"Status + 7seg SoC%\";\n        break;\n    case 3:\n        msg.payload.HwExpansionNeoPixelMode = \"Solid SoC% 8seg\";\n        break;\n    default:\n        msg.payload.HwExpansionNeoPixelMode = \"Buggered\";\n}\n\nswitch(msg.payload.HwExpansionRelay1) {\n    case 0:\n        msg.payload.HwExpansionRelay1 = \"None\";\n        break;\n    case 1:\n        msg.payload.HwExpansionRelay1 = \"ManualOn\";\n        break;\n    case 2:\n        msg.payload.HwExpansionRelay1 = \"Critical BattOk\";\n        break;\n    case 3:\n        msg.payload.HwExpansionRelay1 = \"Charging On\";\n        break;\n    case 4:\n        msg.payload.HwExpansionRelay1 = \"Discharging On\";\n        break;\n    case 5:\n        msg.payload.HwExpansionRelay1 = \"Heating Required\";\n        break;\n    case 6:\n        msg.payload.HwExpansionRelay1 = \"Cooling Required\";\n        break;\n    case 7:\n        msg.payload.HwExpansionRelay1 = \"Run / Idle input\";\n        break;\n    case 8:\n        msg.payload.HwExpansionRelay1 = \"Charge / Normal input\";\n        break;\n    case 9:\n        msg.payload.HwExpansionRelay1 = \"Bypass Complete\";\n        break;\n    case 10:\n        msg.payload.HwExpansionRelay1 = \"Charging Limited\";\n        break;\n    case 11:\n        msg.payload.HwExpansionRelay1 = \"Discharging Limited\";\n        break;\n    case 12:\n        msg.payload.HwExpansionRelay1 = \"Critical Recovery\";\n        break;\n    case 13:\n        msg.payload.HwExpansionRelay1 = \"Critical PulseOn\";\n        break;\n    case 14:\n        msg.payload.HwExpansionRelay1 = \"Critical PulseOff\";\n        break;\n    case 105:\n        msg.payload.HwExpansionRelay1 = \"Critical Fault\";\n        break;\n    case 16:\n        msg.payload.HwExpansionRelay1 = \"Critical PrechargeTimer\";\n        break;\n    default:\n        msg.payload.HwExpansionRelay1 = \"Buggered\";\n}\n\nswitch(msg.payload.HwExpansionInput1) {\n    case 0:\n        msg.payload.HwExpansionInput1 = \"None\";\n        break;\n    case 1:\n        msg.payload.HwExpansionInput1 = \"Run / Idle mode\";\n        break;\n    case 2:\n        msg.payload.HwExpansionInput1 = \"Charge / Normal mode\";\n        break;\n    case 3:\n        msg.payload.HwExpansionInput1 = \"Critical contact sensor - On\";\n        break;\n    case 4:\n        msg.payload.HwExpansionInput1 = \"Critical contact sensor - Fault\";\n        break;\n    default:\n        msg.payload.HwExpansionInput1 = \"Buggered\";\n}\n\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 130,
        "y": 780,
        "wires": [
            [
                "1b2080a0.f3533f"
            ]
        ]
    },
    {
        "id": "1b2080a0.f3533f",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 780,
        "wires": []
    },
    {
        "id": "31f8d71a.f97f68",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_4b35_HwCellGroupSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8('HwCellmonSetupVers')  \n\t\t.uint8('HwCellmonBattTypeID')  /* BattTypes\n\t\t\t\tCustom \t\t\t\t= 0,\n\t\t\t\tLi-FePO4 Typical \t= 1,\n\t\t\t\tLi-Ion Performance \t= 2,\n\t\t\t\tLi-Ion LongLife \t= 3, \n\t\t\t\tLi-FePO4 Longlife \t= 4, */\n\t\t.uint8(  'HwCellmonFirstID')  \n\t\t.uint8(  'HwCellmonLastID')  \t\n\t\t.int16le('HwCellmonNomCellVolt', \t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('HwCellmonLoCellVolt', \t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('HwCellmonHiCellVolt',\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('HwCellmonBypassVoltLevel',\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('HwCellmonBypassAmpLimit', \t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8( 'HwCellmonBypassTempLimit',\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8( 'HwCellmonLoCellTemp',\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8( 'HwCellmonHiCellTemp',\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8( 'HwCellmonDiffNomCellsInSeries')  \t// Boolean 0 = Off , 1 = On\n\t\t.uint8( 'HwCellmonNomCellsInSeries') \n\t\t.uint8( 'HwCellmonAllowEntireRange')  \t\t// Boolean 0 = Off , 1 = On\n\t\t.uint8( 'HwCellmonEntireFirstID')  \n\t\t.uint8( 'HwCellmonEntireLastID')  \n\t\t.uint8( 'HwCellmonBypassExtraMode')  /* BypassExtraModes\n\t\t\t\tNone \t\t\t= 0,\n\t\t\t\tIdle Shunt \t\t= 1,\n\t\t\t\tSame CellVolt \t= 2,\n\t\t\t\tAutoLevel \t\t= 3, */\n\t\t.int16le('HwCellmonBypassExtraInterval',\t\t{ formatter: (x) => {return x/1000;}}) \t// seconds\n\t\t.uint8(  'HwCellmonCellMonTypeID')  /* CellMonTypes\n\t\t\t\tCustom \t\t= 0,\n\t\t\t\tGenMon 2W \t= 1,\n\t\t\t\tGenMon 8W \t= 2,\n\t\t\t\tLongMon \t= 3,\n\t\t\t\tBlockMonM8 \t= 4,\n\t\t\t\tBlockMonM14 = 5,\n\t\t\t\tEndMon \t\t= 6,\n\t\t\t\tManyMon \t= 7, */\n\t\t.floatle('HwCellmonBypassImpedance', \t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('HwCellmonBypassLoVoltCutout', \t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('HwCellmonBypassShuntChargeLimit', \t{ formatter: (x) => {return x/100;}}) \t// amps\n\t\t.int16le('HwCellmonBypassShuntDischgLimit', \t{ formatter: (x) => {return x/100;}}) \t// amps\n\t\t.uint8(  'HwCellmonBypassShuntSocLo', \t\t\t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.int16le('HwCellmonBypassCellVoltBanding', \t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('HwCellmonBypassCellVoltDiff', \t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('HwCellmonBypassStableInterval',\t\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.int16le('HwCellmonBypassExtraAmpLimit', \t\t{ formatter: (x) => {return x/1000;}}) // amps\n\n  \nmsg.payload = typea.parse(buf);\n\nswitch(msg.payload.HwCellmonBattTypeID) {\n    case 0:\n        msg.payload.HwCellmonBattTypeID = \"Custom\";\n        break;\n    case 1:\n        msg.payload.HwCellmonBattTypeID = \"Li-FePO4 Typical\";\n        break;\n    case 2:\n        msg.payload.HwCellmonBattTypeID = \"Li-Ion Performance\";\n        break;\n    case 3:\n        msg.payload.HwCellmonBattTypeID = \"Li-Ion LongLife\";\n        break;\n    case 4:\n        msg.payload.HwCellmonBattTypeID = \"Li-FePO4 Longlife\";\n        break;\n    default:\n        msg.payload.HwCellmonBattTypeID = \"Buggered\";\n}\n\nswitch(msg.payload.HwCellmonBypassExtraMode) {\n    case 0:\n        msg.payload.HwCellmonBypassExtraMode = \"None\";\n        break;\n    case 1:\n        msg.payload.HwCellmonBypassExtraMode = \"Idle Shunt\";\n        break;\n    case 2:\n        msg.payload.HwCellmonBypassExtraMode = \"Same CellVolt\";\n        break;\n    case 3:\n        msg.payload.HwCellmonBypassExtraMode = \"AutoLevel\";\n        break;\n    default:\n        msg.payload.HwCellmonBypassExtraMode = \"Buggered\";\n}\n\nswitch(msg.payload.HwCellmonCellMonTypeID) {\n    case 0:\n        msg.payload.HwCellmonCellMonTypeID = \"Custom\";\n        break;\n    case 1:\n        msg.payload.HwCellmonCellMonTypeID = \"GenMon 2W\";\n        break;\n    case 2:\n        msg.payload.HwCellmonCellMonTypeID = \"GenMon 8W\";\n        break;\n    case 3:\n        msg.payload.HwCellmonCellMonTypeID = \"LongMon\";\n        break;\n    case 4:\n        msg.payload.HwCellmonCellMonTypeID = \"BlockMonM8\";\n        break;\n    case 5:\n        msg.payload.HwCellmonCellMonTypeID = \"BlockMonM14\";\n        break;\n    case 6:\n        msg.payload.HwCellmonCellMonTypeID = \"EndMon\";\n        break;\n    case 7:\n        msg.payload.HwCellmonCellMonTypeID = \"ManyMon\";\n        break;\n    default:\n        msg.payload.HwCellmonCellMonTypeID = \"Buggered\";\n}\n\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 130,
        "y": 700,
        "wires": [
            [
                "fbba11c0.1f358"
            ]
        ]
    },
    {
        "id": "6bbf2b60.9ce744",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_4c33_HwShuntSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8('HwShuntShuntType')  /* ShuntTypes\n\t\t\t\tNone            \t\t\t\t= 0,\n\t\t\t\tSFP102MOD 100uOhm 375A 150V \t= 1, \n\t\t\t\tSFP101EVB 72uOhm 500A 150V     \t= 2,\n\t\t\t\tSFP101EVB 25uOhm 1500A 150V \t= 3,\n\t\t\t\tSFP102MOD (4k) 375A 750V  \t\t= 4, \n\t\t\t\tSFP102MOD (3k) 375A 600V   \t\t= 5, \n\t\t\t\tSFP102MOD Negative volt sense  \t= 6,\n\t\t\t\tSFP102MOD 50uOhm 750A 150V \t\t= 7, \n\t\t\t\tShuntMon2 50uOhm 500A 650V \t\t= 16, */\n\t\t.int16le('HwShuntScale16volt')\n\t\t.int16le('HwShuntScale16amp')\n\t\t.int16le('HwShuntChargeIdle',\t{ formatter: (x) => {return x/100;}})   // amps\n\t\t.int16le('HwShuntDischgIdle',\t{ formatter: (x) => {return x/100;}})\t// amps\n\t\t.uint8( 'HwShuntSocCountLo', \t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.uint8( 'HwShuntSocCountHi', \t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.uint8( 'HwShuntSocLoRecal', \t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.uint8( 'HwShuntSocHiRecal', \t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.uint8( 'HwShuntMonitorSocLoRecal') \t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'HwShuntMonitorSocHiRecal') \t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'HwShuntMonitorInBypassRecal')\t// boolean 0 = Off , 1 = On\n\t\t.floatle('HwShuntNomCapacity',\t{ formatter: (x) => {return x/1000;}})\t// Ah\n\t\t.floatle('HwShuntGainVolt')\n\t\t.floatle('HwShuntGainAmp')\n\t\t.floatle('HwShuntGainAcculm')\t// mAh\n\t\t.floatle('HwShuntGainTemp') \t// temperature ºC\n\t\t.uint8( 'HwShuntReverseFlow') \t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'HwShuntSetupVers') \n\t\t.floatle('HwShuntGainVA')\n\t\t.floatle('HwShuntGainVAh')\t\n\t\t.int16le('HwShuntMax16volt')\n\t\t.int16le('HwShuntMax16charge')\n\t\t.int16le('HwShuntMax16dischg')\n\n  \nmsg.payload = typea.parse(buf);\n\nswitch(msg.payload.HwShuntShuntType) {\n    case 0:\n        msg.payload.HwShuntShuntType = \"None\";\n        break;\n    case 1:\n        msg.payload.HwShuntShuntType = \"SFP102MOD 100uOhm 375A 150V\";\n        break;\n    case 2:\n        msg.payload.HwShuntShuntType = \"SFP101EVB 72uOhm 500A 150V\";\n        break;\n    case 3:\n        msg.payload.HwShuntShuntType = \"SFP101EVB 25uOhm 1500A 150V\";\n        break;\n    case 4:\n        msg.payload.HwShuntShuntType = \"SFP102MOD (4k) 375A 750V\";\n        break;\n    case 5:\n        msg.payload.HwShuntShuntType = \"SFP102MOD (3k) 375A 600V\";\n        break;\n    case 6:\n        msg.payload.HwShuntShuntType = \"SFP102MOD Negative volt sense\";\n        break;\n    case 7:\n        msg.payload.HwShuntShuntType = \"SFP102MOD 50uOhm 750A 150V\";\n        break;\n    case 16:\n        msg.payload.HwShuntShuntType = \"ShuntMon2 50uOhm 500A 650V\";\n        break;\n    default:\n        msg.payload.HwShuntShuntType = \"Buggered\";\n}\n\n\n\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 120,
        "y": 740,
        "wires": [
            [
                "22e7b26a.4c54ae"
            ]
        ]
    },
    {
        "id": "bc74a308.cfe11",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_5334_HwIntegrationSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8('HwIntegrationSetupVers')  \n\t\t.uint8('HwIntegrationUsbTxBroadcast')  \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8('HwIntegrationWifiUdpTxBroadcast') \t// boolean 0 = Off , 1 = On\n\t\t.uint8('HwIntegrationWifiBroadcastMode') /* WifiBroadcastModes\n\t\t\t\tNone \t\t= 0,\n\t\t\t\tVerbose \t= 1,\n\t\t\t\tVerbose ReadOnly = 4,\n\t\t\t\tLimited \t= 2,\n\t\t\t\tDisabled \t= 3, */\n\t\t.uint8('HwIntegrationCanbusTxBroadcast') \t// boolean 0 = Off , 1 = On\n\t\t.uint8('HwIntegrationCanbusMode') /* CanbusModes\n\t\t\t\tNone   \t\t= 0,\n\t\t\t\tNative \t\t= 1,\n\t\t\t\tElcon TCCharger = 2,\n\t\t\t\tEnPower Charger500k = 3,\n\t\t\t\tSolax PowerSK control = 4,\n\t\t\t\tSma SunnyIsland V31 = 5,\n\t\t\t\tBrusa NLG5 \t= 6,\n\t\t\t\tEnPower Charger 250k = 7,\n\t\t\t\tSolax PowerSK Limited = 8,\n\t\t\t\tBrusa NLG6 \t= 9,\n\t\t\t\tProject Lychee = 10,\n\t\t\t\tEltek FlatPack2 HE2000/48 = 11,\n\t\t\t\tProject42 \t= 42,\t*/\n\t\t.uint32le('HwIntegrationCanbusRemoteAddr')\n\t\t.uint32le('HwIntegrationCanbusBaseAddr')\n\t\t.uint32le('HwIntegrationCanbusGroupAddr')\n  \nmsg.payload = typea.parse(buf);\n\nswitch(msg.payload.HwIntegrationWifiBroadcastMode) {\n    case 0:\n        msg.payload.HwIntegrationWifiBroadcastMode = \"None\";\n        break;\n    case 1:\n        msg.payload.HwIntegrationWifiBroadcastMode = \"Verbose\";\n        break;\n    case 2:\n        msg.payload.HwIntegrationWifiBroadcastMode = \"Limited\";\n        break;\n    case 3:\n        msg.payload.HwIntegrationWifiBroadcastMode = \"Disabled\";\n        break;\n    case 4:\n        msg.payload.HwIntegrationWifiBroadcastMode = \"Verbose ReadOnly\";\n        break;\n    default:\n        msg.payload.HwIntegrationWifiBroadcastMode = \"Buggered\";\n}\n\nswitch(msg.payload.HwExpansionRelay1) {\n    case 0:\n        msg.payload.HwExpansionRelay1 = \"None\";\n        break;\n    case 1:\n        msg.payload.HwExpansionRelay1 = \"Native\";\n        break;\n    case 2:\n        msg.payload.HwExpansionRelay1 = \"Elcon TCCharger\";\n        break;\n    case 3:\n        msg.payload.HwExpansionRelay1 = \"EnPower Charger500k\";\n        break;\n    case 4:\n        msg.payload.HwExpansionRelay1 = \"Solax PowerSK control\";\n        break;\n    case 5:\n        msg.payload.HwExpansionRelay1 = \"Sma SunnyIsland V31\";\n        break;\n    case 6:\n        msg.payload.HwExpansionRelay1 = \"Brusa NLG5\";\n        break;\n    case 7:\n        msg.payload.HwExpansionRelay1 = \"EnPower Charger 250k\";\n        break;\n    case 8:\n        msg.payload.HwExpansionRelay1 = \"Solax PowerSK Limited\";\n        break;\n    case 9:\n        msg.payload.HwExpansionRelay1 = \"Brusa NLG6\";\n        break;\n    case 10:\n        msg.payload.HwExpansionRelay1 = \"Project Lychee\";\n        break;\n    case 11:\n        msg.payload.HwExpansionRelay1 = \"Eltek FlatPack2 HE2000/48\";\n        break;\n    case 42:\n        msg.payload.HwExpansionRelay1 = \"roject42\";\n        break;\n    default:\n        msg.payload.HwExpansionRelay1 = \"Buggered\";\n}\n\n\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 130,
        "y": 820,
        "wires": [
            [
                "8b53a6b9.a53688"
            ]
        ]
    },
    {
        "id": "8b53a6b9.a53688",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 820,
        "wires": []
    },
    {
        "id": "a3320528.870448",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_4f33_ControlCriticalSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8( 'ControlCriticalMode')   /* Choices ControlCriticalModes\n\t\t\t\tAuto \t\t\t= 0,\n\t\t\t\tManually On \t= 1,\n\t\t\t\tManually Off  \t= 2, */\t\n\t\t.uint8( 'ControlCriticalAutoRecovery')  \t\t\t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'ControlCriticalIgnoreCellsOverdue') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'ControlCriticalMonitorCellVoltLo') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'ControlCriticalMonitorCellVoltHi') \t\t// boolean 0 = Off , 1 = On\n\t\t.int16le('ControlCriticalCellVoltLo',\t\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('ControlCriticalCellVoltHi',\t\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8( 'ControlCriticalMonitorCellTempLo') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'ControlCriticalMonitorCellTempHi') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'ControlCriticalCellTempLo',\t\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8( 'ControlCriticalCellTempHi',\t\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8( 'ControlCriticalMonitorSupplyLo') \t\t\t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'ControlCriticalMonitorSupplyHi') \t\t\t// boolean 0 = Off , 1 = On\n\t\t.int16le('ControlCriticalSupplyVoltLo',\t\t\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('ControlCriticalSupplyVoltHi',\t\t\t\t{ formatter: (x) => {return x/100;}})\n\t\t.uint8( 'ControlCriticalMonitorAmbientLo') \t\t\t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'ControlCriticalMonitorAmbientHi') \t\t\t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'ControlCriticalAmbientTempLo',\t\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8( 'ControlCriticalAmbientTempHi',\t\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8( 'ControlCriticalMonitorShuntVoltLo') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'ControlCriticalMonitorShuntVoltHi') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8( 'ControlCriticalMonitorShuntVoltLoIdle') \t// boolean 0 = Off , 1 = On\n\t\t.int16le('ControlCriticalShuntVoltLo',\t\t\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('ControlCriticalShuntVoltHi',\t\t\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('ControlCriticalShuntVoltLoIdle',\t\t\t{ formatter: (x) => {return x/100;}})\n\t\t.uint8(  'ControlCriticalMonitorShuntPeakCharge') \t// boolean 0 = Off , 1 = On\n\t\t.int16le('ControlCriticalShuntPeakCharge',\t\t\t{ formatter: (x) => {return x/100;}}) // amps\n\t\t.int16le('ControlCriticalShuntCrateCharge',\t\t\t{ formatter: (x) => {return x/100;}}) // ratio\n\t\t.uint8(  'ControlCriticalMonitorShuntPeakDischg') \t// boolean 0 = Off , 1 = On\n\t\t.int16le('ControlCriticalShuntPeakDischg',\t\t\t{ formatter: (x) => {return x/100;}}) // amps\n\t\t.int16le('ControlCriticalShuntCrateDischg',\t\t\t{ formatter: (x) => {return x/100;}}) // ratio\n\t\t.uint32le('ControlCriticalStopInterval',\t\t\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint32le('ControlCriticalStartInterval',\t\t\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint32le('ControlCriticalTimeoutManualOverride',\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint32le('ControlCriticalPrechargeTimeInterval',\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint8(  'ControlCriticalIgnoreShuntOverdue') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8(  'ControlCriticalIgnoreRemoteOverdue') \t\t// boolean 0 = Off , 1 = On\n\t\t.int16le('ControlCriticalRecoverSupplyGapVolt',\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('ControlCriticalRecoverShuntChargeLimit',\t{ formatter: (x) => {return x/100;}}) // amps\n\t\t.int16le('ControlCriticalRecoverShuntDischgLimit',\t{ formatter: (x) => {return x/100;}}) // amps\n\t\t.uint8(  'ControlCriticalSetupVers') \n\n  \nmsg.payload = typea.parse(buf);\n\nswitch(msg.payload.ControlCriticalMode) {\n    case 0:\n        msg.payload.ControlCriticalMode = \"Auto\";\n        break;\n    case 1:\n        msg.payload.ControlCriticalMode = \"Manually On\";\n        break;\n    case 2:\n        msg.payload.ControlCriticalMode = \"Manually Off\";\n        break;\n    default:\n        msg.payload.ControlCriticalMode = \"Buggered\";\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 130,
        "y": 860,
        "wires": [
            [
                "86100b5d.5d6998"
            ]
        ]
    },
    {
        "id": "86100b5d.5d6998",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 860,
        "wires": []
    },
    {
        "id": "84398b42.b2f578",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_5033_ControlChargeSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8( 'ControlChargeMode')  /* Choices ControlChargeModes\n\t\t\t\tAuto\t\t  \t = 0,\n\t\t\t\tManually On      = 1,\n\t\t\t\tManually Off     = 2,\n\t\t\t\tManually Limited = 3, */\t\n\t\t.uint8(  'ControlChargeAllowLimPowerStage')  \t// boolean 0 = Off , 1 = On\n\t\t.uint8(  'ControlChargeAllowBypassLimPower') \t// boolean 0 = Off , 1 = On\n\t\t.uint8(  'ControlChargeAllowBypassComplete') \t// boolean 0 = Off , 1 = On\n\t\t.int16le('ControlChargeInitalBypassAmp',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('ControlChargeFinalBypassAmp',\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8(  'ControlChargeMonitorCellTempLo') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8(  'ControlChargeMonitorCellTempHi') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8(  'ControlChargeCellTempLo',\t\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8(  'ControlChargeCellTempHi',\t\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8(  'ControlChargeMonitorAmbientLo') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8(  'ControlChargeMonitorAmbientHi') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8(  'ControlChargeAmbientTempLo',\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8(  'ControlChargeAmbientTempHi',\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8(  'ControlChargeMonitorSupplyHi') \t\t// boolean 0 = Off , 1 = On\n\t\t.int16le('ControlChargeSupplyVoltHi',\t\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('ControlChargeSupplyVoltResume',\t\t{ formatter: (x) => {return x/100;}})\n\t\t.uint8(  'ControlChargeMonitorCellVoltHi') \t\t// boolean 0 = Off , 1 = On\n\t\t.int16le('ControlChargeCellVoltHi',\t\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('ControlChargeCellVoltResume',\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('ControlChargeCellVoltLimPower',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8(  'ControlChargeMonitorShuntVoltHi') \t// boolean 0 = Off , 1 = On\n\t\t.int16le('ControlChargeShuntVoltHi',\t\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('ControlChargeShuntVoltResume',\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('ControlChargeShuntVoltLimPower',\t\t{ formatter: (x) => {return x/100;}})\n\t\t.uint8(  'ControlChargeMonitorShuntSocHi') \t\t// boolean 0 = Off , 1 = On\n\t\t.uint8(  'ControlChargeShuntSocHi', \t\t\t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.uint8(  'ControlChargeShuntSocResume', \t\t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.uint32le('ControlChargeStopInterval',\t\t\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint32le('ControlChargeStartInterval',\t\t\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint8(  'ControlChargeSetupVers')  \n\t\t.floatle('ControlChargeBypassSessionLo',\t\t{ formatter: (x) => {return x/1000;}})\t// Ah\n\t\t.uint8(  'ControlChargeAllowBypassSession') \t// boolean 0 = Off , 1 = On\n\t\t\n  \nmsg.payload = typea.parse(buf);\n\nswitch(msg.payload.ControlChargeMode) {\n    case 0:\n        msg.payload.ControlChargeMode = \"Auto\";\n        break;\n    case 1:\n        msg.payload.ControlChargeMode = \"Manually On\";\n        break;\n    case 2:\n        msg.payload.ControlChargeMode = \"Manually Off\";\n        break;\n    case 3:\n        msg.payload.ControlChargeMode = \"Manually Limited\";\n        break;\n    default:\n        msg.payload.ControlChargeMode = \"Buggered\";\n}\n\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 130,
        "y": 900,
        "wires": [
            [
                "e91ed1d6.85832"
            ]
        ]
    },
    {
        "id": "e91ed1d6.85832",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 900,
        "wires": []
    },
    {
        "id": "66113e17.06931",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "Msg_5158_ControlDischargeSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8(   'ControlDischargeMode') /* Choices ControlDischgModes\n\t\t\t\tAuto\t\t  \t = 0,\n\t\t\t\tManually On      = 1,\n\t\t\t\tManually Off     = 2,\n\t\t\t\tManually Limited = 3, */\t\n\t\t.uint8(   'ControlDischargeAllowLimPowerStage')\t// boolean 0 = Off , 1 = On\n\t\t.uint8(   'ControlDischargeMonitorCellTempLo') \t// boolean 0 = Off , 1 = On\n\t\t.uint8(   'ControlDischargeMonitorCellTempHi') \t// boolean 0 = Off , 1 = On\n\t\t.uint8(   'ControlDischargeCellTempLo',\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8(   'ControlDischargeCellTempHi',\t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8(   'ControlDischargeMonitorAmbientLo') \t// boolean 0 = Off , 1 = On\n\t\t.uint8(   'ControlDischargeMonitorAmbientHi') \t// boolean 0 = Off , 1 = On\n\t\t.uint8(   'ControlDischargeAmbientTempLo',\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8(   'ControlDischargeAmbientTempHi',\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8(   'ControlDischargeMonitorSupplyLo') \t// boolean 0 = Off , 1 = On\n\t\t.int16le( 'ControlDischargeSupplyVoltLo',\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le( 'ControlDischargeSupplyVoltResume',\t{ formatter: (x) => {return x/100;}})\n\t\t.uint8(   'ControlDischargeMonitorCellVoltLo') \t// boolean 0 = Off , 1 = On\n\t\t.int16le( 'ControlDischargeCellVoltLo',\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le( 'ControlDischargeCellVoltResume',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le( 'ControlDischargeCellVoltLimPower',\t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8(   'ControlDischargeMonitorShuntVoltLo') // boolean 0 = Off , 1 = On\n\t\t.int16le( 'ControlDischargeShuntVoltLo',\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le( 'ControlDischargeShuntVoltResume',\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le( 'ControlDischargeShuntVoltLimPower',\t{ formatter: (x) => {return x/100;}})\n\t\t.uint8(   'ControlDischargeMonitorShuntSocLo') \t// boolean 0 = Off , 1 = On\n\t\t.uint8(   'ControlDischargeShuntSocLo', \t\t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.uint8(   'ControlDischargeShuntSocResume', \t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.uint32le('ControlDischargeStopInterval',\t\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint32le('ControlDischargeStartInterval',\t\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint8(   'ControlDischargeSetupVers')  \n\t\n  \nmsg.payload = typea.parse(buf);\n\nswitch(msg.payload.ControlDischargeMode) {\n    case 0:\n        msg.payload.ControlDischargeMode = \"Auto\";\n        break;\n    case 1:\n        msg.payload.ControlDischargeMode = \"Manually On\";\n        break;\n    case 2:\n        msg.payload.ControlDischargeMode = \"Manually Off\";\n        break;\n    case 3:\n        msg.payload.ControlDischargeMode = \"Manually Limited\";\n        break;\n    default:\n        msg.payload.ControlDischargeMode = \"Buggered\";\n}\n\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 140,
        "y": 940,
        "wires": [
            [
                "e0549ade.d61068"
            ]
        ]
    },
    {
        "id": "e0549ade.d61068",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 940,
        "wires": []
    },
    {
        "id": "d0a120ad.f8edd",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_5258_ControlThermalSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8('ControlHeatMode')  /* Choices ThermalControlModes\n\t\t\t\tAuto\t\t  \t = 0,\n\t\t\t\tManually On      = 1,\n\t\t\t\tManually Off     = 2, */\t\n\t\t.uint8('ControlHeatMonitorLoCellTemp')  \t// Boolean 0 = Off , 1 = On\n\t\t.uint8('ControlHeatMonitorLoAmbient')  \t\t// Boolean 0 = Off , 1 = On\n\t\t.uint8('ControlHeatLoCellTemp', \t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('ControlHeatLoAmbient',\t \t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint32le('ControlHeatStopInterval',\t\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint32le('ControlHeatStartInterval',\t\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint8('ControlCoolMode')  \t\t\t\t\t/* Choices ThermalControlModes */\n\t\t.uint8('ControlCoolMonitorHiCellTemp')  \t// Boolean 0 = Off , 1 = On\n\t\t.uint8('ControlCoolMonitorHiAmbient')   \t// Boolean 0 = Off , 1 = On\n\t\t.uint8('ControlCoolMonitorInBypass')   \t\t// Boolean 0 = Off , 1 = On\n\t\t.uint8('ControlCoolHiCellTemp', \t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint8('ControlCoolHiAmbient',\t \t\t\t{ formatter: (x) => {return x-40;}}) // temperature ºC\n\t\t.uint32le('ControlCoolStopInterval',\t\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint32le('ControlCoolStartInterval',\t\t{ formatter: (x) => {return x/1000;}}) // seconds\n\t\t.uint8('ControlThermalSetupVers')  \n\n  \nmsg.payload = typea.parse(buf);\n\nswitch(msg.payload.ControlHeatMode) {\n    case 0:\n        msg.payload.ControlHeatMode = \"Auto\";\n        break;\n    case 1:\n        msg.payload.ControlHeatMode = \"Manually On\";\n        break;\n    case 2:\n        msg.payload.ControlHeatMode = \"Manually Off\";\n        break;\n    default:\n        msg.payload.ControlHeatMode = \"Buggered\";\n}\n\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 140,
        "y": 980,
        "wires": [
            [
                "6bb53cb7.1587d4"
            ]
        ]
    },
    {
        "id": "6bb53cb7.1587d4",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 980,
        "wires": []
    },
    {
        "id": "3f60dd09.a9d822",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_4e58_ControlRemoteSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.int16le('ControlChargeTargetNormVolt')\n\t\t.int16le('ControlChargeTargetNormAmp')\n\t\t.int16le('ControlChargeTargetNormVA')\n\t\t.int16le('ControlChargeTargetLimpVolt')\n\t\t.int16le('ControlChargeTargetLimpAmp')\n\t\t.int16le('ControlChargeTargetLimpVA')\n\t\t.int16le('ControlChargeScale16volt')\n\t\t.int16le('ControlChargeScale16amp')\n\t\t.int16le('ControlChargeScale16va')\n\t\t.int16le('ControlDischargeTargetNormVolt')\n\t\t.int16le('ControlDischargeTargetNormAmp')\n\t\t.int16le('ControlDischargeTargetNormVA')\n\t\t.int16le('ControlDischargeTargetLimpVolt')\n\t\t.int16le('ControlDischargeTargetLimpAmp')\n\t\t.int16le('ControlDischargeTargetLimpVA')\n\t\t.int16le('ControlDischargeScale16volt')\n\t\t.int16le('ControlDischargeScale16amp')\n\t\t.int16le('ControlDischargeScale16va')\n\t\t.uint8('ControlRemoteSetupVers')  \n\t\t\nmsg.payload = typea.parse(buf);\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 140,
        "y": 1020,
        "wires": [
            [
                "77fa4a8.4d5f4b4"
            ]
        ]
    },
    {
        "id": "77fa4a8.4d5f4b4",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 1020,
        "wires": []
    },
    {
        "id": "672f0abe.f9af24",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_5831_DailySessionHist",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.int16le('DailySessionHistId')\n\t\t.uint32le('DailySessionHistTime') \t\t// Epoch   *** log key ***\n\t\t.uint8('DailySessionHistCriticalEvents')\n\t\t.skip(1)\n\t\t.uint8('DailySessionHistMinReportTemp',\t\t\t{ formatter: (x) => {return x-40;}})\t// temperature ºC\n\t\t.uint8('DailySessionHistMaxReportTemp',\t\t\t{ formatter: (x) => {return x-40;}})\t// temperature ºC\n\t\t.uint8('DailySessionHistMinShuntSoc', \t\t\t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.uint8('DailySessionHistMaxShuntSoc', \t\t\t{ formatter: (x) => {return (x-5)/2;}}) // percent\n\t\t.int16le('DailySessionHistMinCellVolt',\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('DailySessionHistMaxCellVolt',\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('DailySessionHistMinSupplyVolt',\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('DailySessionHistMaxSupplyVolt',\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('DailySessionHistMinShuntVolt',\t\t{ formatter: (x) => {return x/100;}})\n\t\t.int16le('DailySessionHistMaxShuntVolt',\t\t{ formatter: (x) => {return x/100;}})\n\t\t.uint8('DailySessionHistThermalBandA',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistThermalBandB',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistThermalBandC',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistThermalBandD',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistThermalBandE',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistThermalBandF',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistThermalBandG',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistThermalBandH',\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistSocBandA',\t\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistSocBandB',\t\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistSocBandC',\t\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistSocBandD',\t\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistSocBandE',\t\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistSocBandF',\t\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistSocBandG',\t\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.uint8('DailySessionHistSocBandH',\t\t\t\t{ formatter: (x) => {return x/10;}}) // hours\n\t\t.int16le('DailySessionHistShuntPeakCharge',\t\t{ formatter: (x) => {return x/100;}})  // amp\n\t\t.int16le('DailySessionHistShuntPeakDischg',\t\t{ formatter: (x) => {return x/100;}})  // amp\n\t\t.int16le('DailySessionHistCumulShuntAhCharge',\t{ formatter: (x) => {return x/1000;}}) // Ah\n\t\t.int16le('DailySessionHistCumulShuntAhDischg',\t{ formatter: (x) => {return x/1000;}}) // Ah\n\t\t\nmsg.payload = typea.parse(buf);\n\n// convert date(s)\nmsg.payload.DailySessionHistTime = new Date(msg.payload.DailySessionHistTime*1000);\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 120,
        "y": 1060,
        "wires": [
            [
                "f82cb531.002978"
            ]
        ]
    },
    {
        "id": "f82cb531.002978",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 1060,
        "wires": []
    },
    {
        "id": "fa326eca.690b8",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_6831_QuickSessionHist",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.int16le('QuickSessionHistId')\n\t\t.uint32le('QuickSessionHistTime') \t\t// Epoch  *** log key ***\n\t\t.uint8('QuickSessionHistSystemOpState') /* Choices\n\t\t\t\tSimulator = 0,   \t  // LED = rainbow pulse\n\t\t\t\tIdle = 1,        \t  // LED = green slow pulse\n\t\t\t\tDischarging = 2, \t  // LED = green solid \n\t\t\t\tSoC Empty = 3,   \t  // LED = green double blink\n\t\t\t\tCharging = 4,    \t  // LED = blue slow pulse\n\t\t\t\tFull = 5,        \t  // LED = blue double blink\n\t\t\t\tTimeout = 6,     \t  // LED = red solid\n\t\t\t\tCritical Pending = 7, // LED = red fast pulse\n\t\t\t\tCritical Offline = 8, // LED = red slow pulse\n\t\t\t\tMqtt Offline = 9,     // LED = white blink\n\t\t\t\tAuth Setup = 10,      // LED = white solid\n\t\t\t\tShunt Timeout = 11,   // LED = red solid  \t*/\n\t\t.uint8( 'QuickSessionHistControlLogic')  \n\t\t.int16le('QuickSessionHistMinCellVolt',\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('QuickSessionHistMaxCellVolt',\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.int16le('QuickSessionHistAvgCellVolt',\t\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8(  'QuickSessionHistAvgCellTemp',\t\t\t{ formatter: (x) => {return x-40;}})\t// temperature ºC\n\t\t.int16le('QuickSessionHistSocHiRes',\t\t\t{ formatter: (x) => {return x/100;}})\t// percent\n\t\t.int16le('QuickSessionHistShuntVolt',\t\t\t{ formatter: (x) => {return x/100;}})\n\t\t.floatle('QuickSessionHistShuntAmp',\t\t\t{ formatter: (x) => {return x/1000;}})  // amp\n\t\t.uint8(  'QuickSessionHistNumOfCellsInBypass')\n\n\t\nmsg.payload = typea.parse(buf);\n\n// convert date(s)\nmsg.payload.QuickSessionHistTime = new Date(msg.payload.QuickSessionHistTime*1000);\n\nswitch(msg.payload.QuickSessionHistSystemOpState) {\n    case 0:\n        msg.payload.QuickSessionHistSystemOpState = \"Simulator\";\n        break;\n    case 1:\n        msg.payload.QuickSessionHistSystemOpState = \"Idle\";\n        break;\n    case 2:\n        msg.payload.QuickSessionHistSystemOpState = \"Discharging\";\n        break;\n    case 3:\n        msg.payload.QuickSessionHistSystemOpState = \"SoC Empty\";\n        break;\n    case 4:\n        msg.payload.QuickSessionHistSystemOpState = \"Charging\";\n        break;\n    case 5:\n        msg.payload.QuickSessionHistSystemOpState = \"Full\";\n        break;\n    case 6:\n        msg.payload.QuickSessionHistSystemOpState = \"Timeout\";\n        break;\n    case 7:\n        msg.payload.QuickSessionHistSystemOpState = \"CriticalPending\";\n        break;\n    case 8:\n        msg.payload.QuickSessionHistSystemOpState = \"CriticalOffline\";\n        break;\n    case 9:\n        msg.payload.QuickSessionHistSystemOpState = \"MqttOffline\";\n        break;\n    case 10:\n        msg.payload.QuickSessionHistSystemOpState = \"AuthSetup\";\n        break;\n    case 11:\n        msg.payload.QuickSessionHistSystemOpState = \"Shunt Timeout\";\n        break;\n    default:\n        msg.payload.QuickSessionHistSystemOpState = \"Buggered\";\n}\n\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 120,
        "y": 1100,
        "wires": [
            [
                "ea787f02.584ab"
            ]
        ]
    },
    {
        "id": "15f71030.bd9eb",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_5431_SessionMetrics",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint32le('QuickSessRecentTime') \t\t// EPOCH\n\t\t.int16le('QuickSessNumOfRecords')\n\t\t.int16le('QuickSessMaxNumOfRecords')\n\t\t.uint32le('QuickSessionInterval',\t\t{ formatter: (x) => {return x/1000;}})\n\t\t.uint8('AllowQuickSession')  \t\t\t// boolean 0 = Off , 1 = On\n\t\t.int16le('DailySessNumOfRecords')\n\t\t.int16le('DailySessMaxNumOfRecords')\n\n\nmsg.payload = typea.parse(buf);\n\n// convert date(s)\nmsg.payload.QuickSessRecentTime = new Date(msg.payload.QuickSessRecentTime*1000);\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 120,
        "y": 1140,
        "wires": [
            [
                "49be9953.d21e48"
            ]
        ]
    },
    {
        "id": "2af1bf8b.3e7b5",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 570,
        "y": 40,
        "wires": []
    },
    {
        "id": "6c1bb0a6.cde56",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Get the set of saved global variables",
        "func": "\nvar ONE = global.get('ONE') || 0;\nvar TWO = global.get('TWO') || 0;\nvar THREE = global.get('THREE') || 0;\nvar FOUR = global.get('FOUR') || 0;\nvar FIVE = global.get('FIVE') || 0;\nvar SIX = global.get('SIX') || 0;\nvar SEVEN = global.get('SEVEN') || 0;\nvar EIGHT = global.get('EIGHT') || 0;\nvar NINE = global.get('NINE') || 0;\nvar TEN = global.get('TEN') || 0;\nvar ELEVEN = global.get('ELEVEN') || 0;\nvar TWELVE = global.get('TWELVE') || 0;\nvar THIRTEEN = global.get('THIRTEEN') || 0;\nvar FOURTEEN = global.get('FOURTEEN') || 0;\nvar FIFTEEN = global.get('FIFTEEN') || 0;\nvar SIXTEEN = global.get('SIXTEEN') || 0;\n\n\nvar m = {};\nm.labels = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16'];\nm.data = [[ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN,EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN, SIXTEEN]];\nm.series = ['Cell'];\nreturn {payload:[m],topic:msg.topic};",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 890,
        "y": 20,
        "wires": [
            [
                "24fe7cc5.03a284",
                "602b821a.72b6bc"
            ]
        ]
    },
    {
        "id": "24fe7cc5.03a284",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1650,
        "y": 20,
        "wires": []
    },
    {
        "id": "b56a71fb.69c95",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Put cell voltage into globals",
        "func": "var myLongmon;\n\nswitch(msg.payload.ID) {\n    case 1:\n        myLongmon=\"ONE\";\n        break;\n    case 2:\n        myLongmon=\"TWO\";\n        break;\n    case 3:\n        myLongmon=\"THREE\";\n        break;\n    case 4:\n        myLongmon=\"FOUR\";\n        break;\n    case 5:\n        myLongmon=\"FIVE\";\n        break;\n    case 6:\n        myLongmon=\"SIX\";\n        break;\n    case 7:\n        myLongmon=\"SEVEN\";\n        break;\n    case 8:\n        myLongmon=\"EIGHT\";\n        break;\n    case 9:\n        myLongmon=\"NINE\";\n        break;\n    case 10:\n        myLongmon=\"TEN\";\n        break;\n    case 11:\n        myLongmon=\"ELEVEN\";\n        break;\n    case 12:\n        myLongmon=\"TWELVE\";\n        break;\n    case 13:\n        myLongmon=\"THIRTEEN\";\n        break;\n    case 14:\n        myLongmon=\"FOURTEEN\";\n        break;\n    case 15:\n        myLongmon=\"FIFTEEN\";\n        break;\n    case 16:\n        myLongmon=\"SIXTEEN\";\n        break;\n}\n \nglobal.set(myLongmon,msg.payload.MaxCellVolt);    \n     \n//return msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 1440,
        "y": 920,
        "wires": [
            [
                "ee919253.daba5"
            ]
        ]
    },
    {
        "id": "d9a8b490.a039d8",
        "type": "inject",
        "z": "e6fd3a1c.5e9548",
        "name": "Update the chart every 1 second",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "5",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 520,
        "y": 140,
        "wires": [
            [
                "6c1bb0a6.cde56",
                "7c2e474e.4fe348",
                "d54ad04d.f5cb8"
            ]
        ]
    },
    {
        "id": "602b821a.72b6bc",
        "type": "ui_chart",
        "z": "e6fd3a1c.5e9548",
        "name": "Realtime cell voltages",
        "group": "605bdeca.e6347",
        "order": 5,
        "width": "0",
        "height": "0",
        "label": "Cell voltages",
        "chartType": "bar",
        "legend": "false",
        "xformat": "HH:mm:ss",
        "interpolate": "linear",
        "nodata": "No Data",
        "dot": false,
        "ymin": "3",
        "ymax": "4.2",
        "removeOlder": 1,
        "removeOlderPoints": "",
        "removeOlderUnit": "3600",
        "cutout": 0,
        "useOneColor": true,
        "useUTC": false,
        "colors": [
            "#00aaff",
            "#b3dfea",
            "#ff7f0e",
            "#2ca02c",
            "#98df8a",
            "#d62728",
            "#ff9896",
            "#9467bd",
            "#c5b0d5"
        ],
        "outputs": 1,
        "x": 1400,
        "y": 60,
        "wires": [
            [
                "43701535.84212c"
            ]
        ]
    },
    {
        "id": "8445ce7c.09028",
        "type": "ui_text",
        "z": "e6fd3a1c.5e9548",
        "group": "605bdeca.e6347",
        "order": 1,
        "width": "0",
        "height": "0",
        "name": "Shunt Status: ",
        "label": "Shunt Status: ",
        "format": "{{msg.payload.ShuntStatus}}",
        "layout": "row-left",
        "x": 820,
        "y": 600,
        "wires": []
    },
    {
        "id": "34dd4fa2.32065",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "Msg_4732_HwSystemSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n   .skip(8)\n      .uint8('isCriticalBattOkState')                 // Boolean 0 = Off , 1 = On\n      .uint8('isCriticalBattOkCalc')                          // Boolean 0 = Off , 1 = On\n      .uint8('isCriticalTransition')                          // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalCellOverdue')                // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalCellVoltLo')                 // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalCellVoltHi')                 // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalCellTempLo')                 // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalCellTempHi')                 // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalSupplyVoltLo')               // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalSupplyVoltHi')               // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalAmbientLo')                          // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalAmbientHi')                          // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalShuntVoltLo')                // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalShuntVoltHi')                // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalShuntVoltLoIdle')    // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalShuntPeakCharge')    // Boolean 0 = Off , 1 = On\n      .uint8('hasCriticalShuntPeakDischg')    // Boolean 0 = Off , 1 = On\n      .uint8('isChargeOnState')                               // Boolean 0 = Off , 1 = On\n      .uint8('isChargeLimPower')                              // Boolean 0 = Off , 1 = On\n      .uint8('isChargeTransition')                    // Boolean 0 = Off , 1 = On\n      .uint8('isChargePowerRateState') /* Choices ChargeRateStates\n                                Off                     = 0,\n                                Limited Power   = 2,\n                                Normal Power    = 4, */\n      .uint8('isChargePowerRateCalc')                 /* Choices ChargeRateStates */\n      .uint8('hasChargeCellVoltHi ')                          // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeCellVoltPause ')               // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeCellVoltLimPower ')    // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeCellTempLo ')                          // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeCellTempHi ')                          // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeAmbientTempLo ')               // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeAmbientTempHi ')               // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeSupplyVoltHi ')                // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeSupplyVoltPause ')     // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeShuntVoltHi ')                 // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeShuntVoltPause ')              // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeShuntVoltLimPower ')   // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeShuntSocHi ')                          // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeShuntSocPause ')               // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeAboveInitalBypass ')   // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeAboveFinalBypass ')            // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeInBypass ')                    // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeBypassComplete ')              // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeBypassTempRelief ')    // Boolean 0 = Off , 1 = On\n      .uint8('isDischgOnState ')                              // Boolean 0 = Off , 1 = On\n      .uint8('isDischgLimPower ')                     // Boolean 0 = Off , 1 = On\n      .uint8('isDischgTransition ')                   // Boolean 0 = Off , 1 = On\n      .uint8('isDischgPowerRateState ') /* Choices DischgRateStates\n                                Off                     = 0,\n                                Limited Power   = 2,\n                                Normal Power    = 4, */\n      .uint8('isDischgPowerRateCalc ')                /* Choices DischgRateStates */\n      .uint8('hasDischgCellVoltLo ')                          // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgCellVoltPause ')               // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgCellVoltLimPower ')    // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgCellTempLo ')                          // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgCellTempHi ')                          // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgAmbientLo ')                   // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgAmbientHi ')                   // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgSupplyVoltLo ')                // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgSupplyVoltPause ')     // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgShuntVoltLo ')                 // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgShuntVoltPause ')              // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgShuntVoltLimPower ')   // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgShuntSocLo ')                          // Boolean 0 = Off , 1 = On\n      .uint8('hasDischgShuntSocPause ')               // Boolean 0 = Off , 1 = On\n      .uint8('isHeatOnState ')                                // Boolean 0 = Off , 1 = On\n      .uint8('isHeatOnCalc ')                                 // Boolean 0 = Off , 1 = On\n      .uint8('isHeatTransition ')                     // Boolean 0 = Off , 1 = On\n      .uint8('hasHeatAmbientLo ')                     // Boolean 0 = Off , 1 = On\n      .uint8('hasHeatCellTempLo ')                    // Boolean 0 = Off , 1 = On\n      .uint8('isCoolOnState')                                 // Boolean 0 = Off , 1 = On\n      .uint8('isCoolOnCalc')                                          // Boolean 0 = Off , 1 = On\n      .uint8('isCoolTransition')                              // Boolean 0 = Off , 1 = On\n      .uint8('hasCoolAmbientHi ')                     // Boolean 0 = Off , 1 = On\n      .uint8('hasCoolCellTempHi ')                    // Boolean 0 = Off , 1 = On\n      .uint8('hasChargeBypassSessionLo ')    // Boolean 0 = Off , 1 = On\n\nmsg.payload = typea.parse(buf);\n\nswitch(msg.payload.isChargePowerRateState) {\n    case 0:\n        msg.payload.isChargePowerRateState = \"Off\";\n        break;\n    case 2:\n        msg.payload.isChargePowerRateState = \"Limited Power\";\n        break;\n    case 4:\n        msg.payload.isChargePowerRateState = \"Normal Power\";\n        break;\n    default:\n        msg.payload.isChargePowerRateState = \"Buggered\";\n}\n\nswitch(msg.payload.isDischgPowerRateState) {\n    case 0:\n        msg.payload.isDischgPowerRateState = \"Off\";\n        break;\n    case 2:\n        msg.payload.isDischgPowerRateState = \"Limited Power\";\n        break;\n    case 4:\n        msg.payload.isDischgPowerRateState = \"Normal Power\";\n        break;\n    default:\n        msg.payload.isDischgPowerRateState = \"Buggered\";\n}\n\n\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 120,
        "y": 1180,
        "wires": [
            [
                "e07437e.312e7c8"
            ]
        ]
    },
    {
        "id": "e07437e.312e7c8",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 1180,
        "wires": []
    },
    {
        "id": "17a67e5b.e13952",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Msg_4d34_HwExpansionSetup",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\t\t.skip(8)\n\t\t.uint8('HwExpansionSetupVers')  \n\t\t.uint8('HwExpansionTemplate')  /* ExtensionTemplateOptions\n\t\t\t\tNone = 0,\n\t\t\t\tExpansionBoard 12v = 1,\n\t\t\t\tExpansionBoard 48v = 2,\n\t\t\t\tWatchMonCmC v2.0   = 3,\t*/\t\n\t\t.uint8('HwExpansionNeoPixelMode')  /* NeoPixelExtStatusModes\n\t\t\t\tNone \t\t\t\t= 0,\n\t\t\t\tRepeat \t\t\t\t= 1,\n\t\t\t\tStatus + 7seg SoC% \t= 2,\n\t\t\t\tSolid SoC% 8seg \t= 3,\t*/\n\t\t.uint8('HwExpansionRelay1')  /* ExpansionOutputAssignments\n\t\t\t\tNone = 0,\n\t\t\t\tManualOn = 1,\n\t\t\t\tCritical BattOk = 2,\n\t\t\t\tCharging On = 4,\n\t\t\t\tDischarging On = 5,\n\t\t\t\tHeating Required = 6,\n\t\t\t\tCooling Required = 7,\n\t\t\t\tRun / Idle input = 8,\n\t\t\t\tCharge / Normal input = 9,\n\t\t\t\tBypass Complete = 10,\n\t\t\t\tCharging Limited = 11,\n\t\t\t\tDischarging Limited = 12,\n\t\t\t\tCritical Recovery = 13,\n\t\t\t\tCritical PulseOn = 14,\n\t\t\t\tCritical PulseOff = 15,\n\t\t\t\tCritical Fault = 16,\n\t\t\t\tCritical PrechargeTimer = 17, */\n\t\t.uint8('HwExpansionRelay2')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionRelay3')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionRelay4')\t\t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput5')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput5')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput7')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput8')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput9')  \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionOutput10') \t/* ExpansionOutputAssignments */\n\t\t.uint8('HwExpansionInput1')  \t/* ExtensionInputOptions\n\t\t\t\tNone \t\t\t\t\t= 0,\n\t\t\t\tRun / Idle mode \t\t= 1,\n\t\t\t\tCharge / Normal mode \t= 2,\n\t\t\t\tCritical contact sensor - On = 3,\n\t\t\t\tCritical contact sensor - Fault = 4, */\n\t\t.uint8('HwExpansionInput2')  \t/* ExtensionInputOptions */\n\t\t.uint8('HwExpansionInput3')  \t/* ExtensionInputOptions */\n\t\t.uint8('HwExpansionInput4')  \t/* ExtensionInputOptions */\n\t\t.uint8('HwExpansionInput5')  \t/* ExtensionInputOptions */\n\t\t.uint8('HwExpansionInputAIN1') \n\t\t.uint8('HwExpansionInputAIN2') \n\t\t.int16le('HwExpansionCustomFeature1')\n\t\t.int16le('HwExpansionCustomFeature2')\nmsg.payload = typea.parse(buf);\n\nswitch(msg.payload.HwExpansionTemplate) {\n    case 0:\n        msg.payload.HwExpansionTemplate = \"None\";\n        break;\n    case 1:\n        msg.payload.HwExpansionTemplate = \"ExpansionBoard 12v\";\n        break;\n    case 2:\n        msg.payload.HwExpansionTemplate = \"ExpansionBoard 48v\";\n        break;\n    case 3:\n        msg.payload.HwExpansionTemplate = \"WatchMonCmC v2.0\";\n        break;\n    default:\n        msg.payload.HwExpansionTemplate = \"Buggered\";\n}\n\nswitch(msg.payload.HwExpansionNeoPixelMode) {\n    case 0:\n        msg.payload.HwExpansionNeoPixelMode = \"None\";\n        break;\n    case 1:\n        msg.payload.HwExpansionNeoPixelMode = \"Repeat\";\n        break;\n    case 2:\n        msg.payload.HwExpansionNeoPixelMode = \"Status + 7seg SoC%\";\n        break;\n    case 3:\n        msg.payload.HwExpansionNeoPixelMode = \"Solid SoC% 8seg\";\n        break;\n    default:\n        msg.payload.HwExpansionNeoPixelMode = \"Buggered\";\n}\n\nswitch(msg.payload.HwExpansionRelay1) {\n    case 0:\n        msg.payload.HwExpansionRelay1 = \"None\";\n        break;\n    case 1:\n        msg.payload.HwExpansionRelay1 = \"ManualOn\";\n        break;\n    case 2:\n        msg.payload.HwExpansionRelay1 = \"Critical BattOk\";\n        break;\n    case 3:\n        msg.payload.HwExpansionRelay1 = \"Charging On\";\n        break;\n    case 4:\n        msg.payload.HwExpansionRelay1 = \"Discharging On\";\n        break;\n    case 5:\n        msg.payload.HwExpansionRelay1 = \"Heating Required\";\n        break;\n    case 6:\n        msg.payload.HwExpansionRelay1 = \"Cooling Required\";\n        break;\n    case 7:\n        msg.payload.HwExpansionRelay1 = \"Run / Idle input\";\n        break;\n    case 8:\n        msg.payload.HwExpansionRelay1 = \"Charge / Normal input\";\n        break;\n    case 9:\n        msg.payload.HwExpansionRelay1 = \"Bypass Complete\";\n        break;\n    case 10:\n        msg.payload.HwExpansionRelay1 = \"Charging Limited\";\n        break;\n    case 11:\n        msg.payload.HwExpansionRelay1 = \"Discharging Limited\";\n        break;\n    case 12:\n        msg.payload.HwExpansionRelay1 = \"Critical Recovery\";\n        break;\n    case 13:\n        msg.payload.HwExpansionRelay1 = \"Critical PulseOn\";\n        break;\n    case 14:\n        msg.payload.HwExpansionRelay1 = \"Critical PulseOff\";\n        break;\n    case 105:\n        msg.payload.HwExpansionRelay1 = \"Critical Fault\";\n        break;\n    case 16:\n        msg.payload.HwExpansionRelay1 = \"Critical PrechargeTimer\";\n        break;\n    default:\n        msg.payload.HwExpansionRelay1 = \"Buggered\";\n}\n\nswitch(msg.payload.HwExpansionInput1) {\n    case 0:\n        msg.payload.HwExpansionInput1 = \"None\";\n        break;\n    case 1:\n        msg.payload.HwExpansionInput1 = \"Run / Idle mode\";\n        break;\n    case 2:\n        msg.payload.HwExpansionInput1 = \"Charge / Normal mode\";\n        break;\n    case 3:\n        msg.payload.HwExpansionInput1 = \"Critical contact sensor - On\";\n        break;\n    case 4:\n        msg.payload.HwExpansionInput1 = \"Critical contact sensor - Fault\";\n        break;\n    default:\n        msg.payload.HwExpansionInput1 = \"Buggered\";\n}\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 130,
        "y": 1220,
        "wires": [
            [
                "d4d7f79b.18b4d8"
            ]
        ]
    },
    {
        "id": "d4d7f79b.18b4d8",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 1220,
        "wires": []
    },
    {
        "id": "e69dec4b.f16a1",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "Msg_6132_StatusComms",
        "func": "var Packet = global.get('binary_parser');\nvar buf = msg.payload;\n\nvar typea = new Packet()\n\n\t\t.skip(8)\n\t\t.uint32le('SystemTime') // Epoch\n\t\t.uint8('SystemOpStatus') /* Choices\n\t\t\t\tSimulator = 0,   \t  // LED = rainbow pulse\n\t\t\t\tIdle = 1,        \t  // LED = green slow pulse\n\t\t\t\tDischarging = 2, \t  // LED = green solid \n\t\t\t\tSoC Empty = 3,   \t  // LED = green double blink\n\t\t\t\tCharging = 4,    \t  // LED = blue slow pulse\n\t\t\t\tFull = 5,        \t  // LED = blue double blink\n\t\t\t\tTimeout = 6,     \t  // LED = red solid\n\t\t\t\tCritical Pending = 7, // LED = red fast pulse\n\t\t\t\tCritical Offline = 8, // LED = red slow pulse\n\t\t\t\tMqtt Offline = 9,     // LED = white blink\n\t\t\t\tAuth Setup = 10,      // LED = white solid\n\t\t\t\tShunt Timeout = 11,   // LED = red solid  \t*/\n\t\t.uint8('SystemAuthMode') /* Choices\n\t\t\t\tDefault = 0,\n\t\t\t\tTechnician = 1,\n\t\t\t\tFactory = 2, */\n\t\t.int16le('SystemAuthToken')\n\t\t.int16le('SystemAuthRejectTicks')\n\t\t.uint8('WifiState') /* Choices WifiOpStates\n\t\t\t\tBroadcast Start = 0,\n\t\t\t\tBroadcast Prep = 1,\n\t\t\t\tBroadcast TxSetup = 2,\n\t\t\t\tBroadcast Running = 3,\n\t\t\t\tUsbCmd Start = 4,\n\t\t\t\tUsbCmd Running = 5,\n\t\t\t\tUsbCmd PassThru = 6,\n\t\t\t\tUsbProg Start = 7,\n\t\t\t\tUsbProg Running = 8,\n\t\t\t\tUsbProg PassThru = 9,\n\t\t\t\tOffline Start = 10,\n\t\t\t\tOffline Running = 11,\n\t\t\t\tOffline Stop = 12,\n\t\t\t\tLimited Start = 13,\n\t\t\t\tLimited Prep = 14,\n\t\t\t\tLimited Running = 15,\n\t\t\t\tJoinAp Start = 16,\n\t\t\t\tJoinAp Running = 17,\t*/\t\t\n\t\t.uint8('WifiTxCmdTicks') \n\t\t.uint8('WifiRxCmdTicks') \n\t\t.uint8('WifiRxUnknownTicks') \n\t\t.uint8('CanbusOpStatus') /* Choices \n\n\t\t\t\t \t*/\t\t\n\t\t.uint8('CanbusRxStatusTicks')\n\t\t.uint8('CanbusRxUnknownTicks')\n\t\t.uint8('CanbusRxStatusTicks')\n\t\t.uint8('ShuntPollerMode') /* Choices ShuntPollerModes\n\t\t\t\tIdle Start = 0,\n\t\t\t\tIdle = 1,\n\t\t\t\tSync Start = 2,\n\t\t\t\tSync Running = 3,\n\t\t\t\tNormal = 4,\n\t\t\t\tShuntMon2 SetupStart = 5,\n\t\t\t\tShuntMon2 SetupRunning = 6,\n\t\t\t\tShuntMon2 Normal = 7, */\n\t\t.uint8('ShuntStatus') /* Choices  ShuntStatuses\n\t\t\t\tTimeout = 0,\n\t\t\t\tDischarging = 1,\n\t\t\t\tIdle = 2,\n\t\t\t\tCharging = 4 */\n\t\t.uint8('ShuntRxAmpTicks')\n\t\t.uint8('ShuntTxAmpTicks')\n\t\t.uint8('CmuPollerMode') \t    /* Choices\n\t\t\t\tIdle = 0,\n\t\t\t\tNormal = 1,\n\t\t\t\tCollection Start = 2,\n\t\t\t\tCollection Running = 3,\n\t\t\t\tSync Start = 4,\n\t\t\t\tSync Running = 5,\n\t\t\t\tNetworkTest Start = 6,\n\t\t\t\tNetworkTest Running = 9,\n\t\t\t\tBypassTest Start = 7,\n\t\t\t\tBypassTest Running = 8,\n\t\t\t\tRebootAll Start = 10,\n\t\t\t\tRebooting AllDevices = 11,\n\t\t\t\tSimulator Start = 12,\n\t\t\t\tSimulator Running = 13, */\n\t\t\t.uint8('CmuOpStatus') /* Choices */\n\t\t\t.uint8('CmuTxCmdTicks')\n\t\t\t.uint8('CmuRxCmdTicks')\n\nmsg.payload = typea.parse(buf);\n\n// convert date(s)\nmsg.payload.SystemTime = new Date(msg.payload.SystemTime*1000);\n\nswitch(msg.payload.SystemOpStatus) {\n    case 0:\n        msg.payload.SystemOpStatus = \"Simulator\";\n        break;\n    case 1:\n        msg.payload.SystemOpStatus = \"Idle\";\n        break;\n    case 2:\n        msg.payload.SystemOpStatus = \"Discharging\";\n        break;\n    case 3:\n        msg.payload.SystemOpStatus = \"SoC Empty\";\n        break;\n    case 4:\n        msg.payload.SystemOpStatus = \"Charging\";\n        break;\n    case 5:\n        msg.payload.SystemOpStatus = \"Full\";\n        break;\n    case 6:\n        msg.payload.SystemOpStatus = \"Timeout\";\n        break;\n    case 7:\n        msg.payload.SystemOpStatus = \"Critical Pending\";\n        break;\n    case 8:\n        msg.payload.SystemOpStatus = \"Critical Offline\";\n        break;\n    case 9:\n        msg.payload.SystemOpStatus = \"Mqtt Offline\";\n        break;\n    case 10:\n        msg.payload.SystemOpStatus = \"Auth Setup\";\n        break;\n    case 11:\n        msg.payload.SystemOpStatus = \"Shunt Timeout\";\n        break;\n    default:\n        msg.payload.SystemOpStatus = \"Buggered\";\n}\n\nswitch(msg.payload.SystemAuthMode) {\n    case 0:\n        msg.payload.SystemAuthMode = \"Default\";\n        break;\n    case 1:\n        msg.payload.SystemAuthMode = \"Technician\";\n        break;\n    case 2:\n        msg.payload.SystemAuthMode = \"Factory\";\n        break;\n    default:\n        msg.payload.SystemAuthMode = \"Buggered\";\n}\n\nswitch(msg.payload.WifiState) {\n    case 0:\n        msg.payload.WifiState = \"Broadcast Start\";\n        break;\n    case 1:\n        msg.payload.WifiState = \"Broadcast Prep\";\n        break;\n    case 2:\n        msg.payload.WifiState = \"Broadcast TxSetup\";\n        break;\n    case 3:\n        msg.payload.WifiState = \"Broadcast Running\";\n        break;\n    case 4:\n        msg.payload.WifiState = \"UsbCmd Start\";\n        break;\n    case 5:\n        msg.payload.WifiState = \"UsbCmd Running\";\n        break;\n    case 6:\n        msg.payload.WifiState = \"UsbCmd PassThru\";\n        break;\n    case 7:\n        msg.payload.WifiState = \"UsbProg Start\";\n        break;\n    case 8:\n        msg.payload.WifiState = \"UsbProg Running\";\n        break;\n    case 9:\n        msg.payload.WifiState = \"UsbProg PassThru\";\n        break;\n    case 10:\n        msg.payload.WifiState = \"Offline Start\";\n        break;\n    case 11:\n        msg.payload.WifiState = \"Offline Running\";\n        break;\n    case 12:\n        msg.payload.WifiState = \"Offline Stop\";\n        break;\n    case 13:\n        msg.payload.WifiState = \"Limited Start\";\n        break;\n    case 14:\n        msg.payload.WifiState = \"Limited Prep\";\n        break;\n    case 15:\n        msg.payload.WifiState = \"Limited Running\";\n        break;\n    case 16:\n        msg.payload.WifiState = \"JoinAp Start\";\n        break;\n    case 17:\n        msg.payload.WifiState = \"JoinAp Running\";\n        break;\n    default:\n        msg.payload.WifiState = \"Buggered\";\n}\n\nswitch(msg.payload.ShuntPollerMode) {\n    case 0:\n        msg.payload.ShuntPollerMode = \"Idle Start\";\n        break;\n    case 1:\n        msg.payload.ShuntPollerMode = \"Idle\";\n        break;\n    case 2:\n        msg.payload.ShuntPollerMode = \"Sync Start\";\n        break;\n    case 3:\n        msg.payload.ShuntPollerMode = \"Sync Running\";\n        break;\n    case 4:\n        msg.payload.ShuntPollerMode = \"Normal\";\n        break;\n    case 5:\n        msg.payload.ShuntPollerMode = \"ShuntMon2 SetupStart\";\n        break;\n    case 6:\n        msg.payload.ShuntPollerMode = \"ShuntMon2 SetupRunning\";\n        break;\n    case 7:\n        msg.payload.ShuntPollerMode = \"ShuntMon2 Normal\";\n        break;\n    default:\n        msg.payload.ShuntPollerMode = \"Buggered\";\n}\n\nswitch(msg.payload.ShuntStatus) {\n    case 0:\n        msg.payload.ShuntStatus = \"Timeout\";\n        break;\n    case 1:\n        msg.payload.ShuntStatus = \"Discharging\";\n        break;\n    case 2:\n        msg.payload.ShuntStatus = \"Idle\";\n        break;\n    case 4:\n        msg.payload.ShuntStatus = \"Charging\";\n        break;\n    default:\n        msg.payload.ShuntStatus = \"Buggered\";\n}\n/*\nswitch(msg.payload.CmuPollerMode) {\n    case 0:\n        msg.payload.CmuPollerMode = \"Idle\";\n        break;\n    case 1:\n        msg.payload.CmuPollerMode = \"Normal\";\n        break;\n    case 2:\n        msg.payload.CmuPollerMode = \"Collection Start\";\n        break;\n    case 3:\n        msg.payload.CmuPollerMode = \"Collection Running\";\n        break;\n    case 4:\n        msg.payload.CmuPollerMode = \"Sync Start\";\n        break;\n    case 5:\n        msg.payload.CmuPollerMode = \"Sync Running\";\n        break;\n    case 6:\n        msg.payload.CmuPollerMode = \"NetworkTest Start\";\n        break;\n    case 7:\n        msg.payload.CmuPollerMode = \"NetworkTest Running\";\n        break;\n    case 8:\n        msg.payload.CmuPollerMode = \"BypassTest Start\";\n        break;\n    case 9:\n        msg.payload.CmuPollerMode = \"BypassTest Running\";\n        break;\n    case 10:\n        msg.payload.CmuPollerMode = \"RebootAll Start\";\n        break;\n    case 11:\n        msg.payload.CmuPollerMode = \"Rebooting AllDevices\";\n        break;\n    case 12:\n        msg.payload.CmuPollerMode = \"Simulator Start\";\n        break;\n    case 13:\n        msg.payload.CmuPollerMode = \"Simulator Running\";\n        break;\n    default:\n        msg.payload.CmuPollerMode = \"Buggered\";\n}\n*/\n\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 110,
        "y": 1260,
        "wires": [
            [
                "15668e4f.43b272"
            ]
        ]
    },
    {
        "id": "15668e4f.43b272",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 390,
        "y": 1260,
        "wires": []
    },
    {
        "id": "1febde5.094d722",
        "type": "comment",
        "z": "e6fd3a1c.5e9548",
        "name": "Based on Watchmon SW 1.0.30 UDP Outbound protocol",
        "info": "All credit for the parsers to Daniel Römer\nBased on his grafpi project:\nhttp://diytechandrepairs.nu/raspberry-solar/\n\nBatrium WatchMon 4\n\nThe machine running node red must be able \nto acces port 18542 UDP IPv4\n\n",
        "x": 690,
        "y": 240,
        "wires": []
    },
    {
        "id": "b2ab7d4c.b3ddd",
        "type": "ui_text",
        "z": "e6fd3a1c.5e9548",
        "group": "605bdeca.e6347",
        "order": 0,
        "width": "3",
        "height": "2",
        "name": "GroupMinCellVolt",
        "label": "Min Cell Voltage",
        "format": "{{msg.payload.GroupMinCellVolt}}v",
        "layout": "col-center",
        "x": 830,
        "y": 680,
        "wires": []
    },
    {
        "id": "68635fb7.0529d",
        "type": "ui_text",
        "z": "e6fd3a1c.5e9548",
        "group": "605bdeca.e6347",
        "order": 0,
        "width": "3",
        "height": "2",
        "name": "GroupMaxCellVolt",
        "label": "Max Cell Voltage",
        "format": "{{msg.payload.GroupMaxCellVolt}}v",
        "layout": "col-center",
        "x": 830,
        "y": 560,
        "wires": []
    },
    {
        "id": "7c2e474e.4fe348",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Cells Global variables for influx",
        "func": "var ONE = global.get('ONE') || 0;\nvar TWO = global.get('TWO') || 0;\nvar THREE = global.get('THREE') || 0;\nvar FOUR = global.get('FOUR') || 0;\nvar FIVE = global.get('FIVE') || 0;\nvar SIX = global.get('SIX') || 0;\nvar SEVEN = global.get('SEVEN') || 0;\nvar EIGHT = global.get('EIGHT') || 0;\nvar NINE = global.get('NINE') || 0;\nvar TEN = global.get('TEN') || 0;\nvar ELEVEN = global.get('ELEVEN') || 0;\nvar TWELVE = global.get('TWELVE') || 0;\nvar THIRTEEN = global.get('THIRTEEN') || 0;\nvar FOURTEEN = global.get('FOURTEEN') || 0;\nvar FIFTEEN = global.get('FIFTEEN') || 0;\nvar SIXTEEN = global.get('SIXTEEN') || 0;\n\nmsg.payload =\n{\n    Cell1: ONE,\n    Cell2: TWO,\n    Cell3: THREE,\n    Cell4: FOUR,\n    Cell5: FIVE,\n    Cell6: SIX,\n    Cell7: SEVEN,\n    Cell8: EIGHT,\n    Cell9: NINE,\n    Cell10: TEN,\n    Cell11: ELEVEN,\n    Cell12: TWELVE,\n    CELL13: THIRTEEN,\n    CELL14: FOURTEEN,\n    CELL15: FIFTEEN,\n    CELL16: SIXTEEN,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 870,
        "y": 100,
        "wires": [
            [
                "6d22e4f3.72c97c",
                "f27ec1c6.f257"
            ]
        ]
    },
    {
        "id": "6d22e4f3.72c97c",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 100,
        "wires": []
    },
    {
        "id": "f27ec1c6.f257",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "bafffa78.f7bbc8",
        "name": "Cell_Voltage",
        "measurement": "Cell_Voltage",
        "precision": "",
        "retentionPolicy": "",
        "database": "",
        "retentionPolicyV18Flux": "",
        "org": "",
        "bucket": "",
        "x": 1430,
        "y": 120,
        "wires": []
    },
    {
        "id": "684ac7ee.c50fc8",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "DailyCumulShuntAh_C_D Influx",
        "func": "var CSAD  = 0;\nvar CSAC  = 0;\nCSAD = Number(msg.payload.DailySessionCumulShuntAhDischg);\nCSAC = Number(msg.payload.DailySessionCumulShuntAhCharge);\nmsg.payload =\n{\n    CumulShuntAhDischg: CSAD,\n    CumulShuntAhCharge: CSAC,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 1190,
        "y": 540,
        "wires": [
            [
                "b957de47.0dd2f",
                "a2d070e7.f7336"
            ]
        ]
    },
    {
        "id": "b957de47.0dd2f",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "bafffa78.f7bbc8",
        "name": "CumulShuntAh_C_D",
        "measurement": "CumulShuntAh_C_D",
        "precision": "",
        "retentionPolicy": "",
        "x": 1460,
        "y": 560,
        "wires": []
    },
    {
        "id": "a2d070e7.f7336",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 1650,
        "y": 540,
        "wires": []
    },
    {
        "id": "b7222b59.93edf8",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Cell_Min_Max_Avg Influx",
        "func": "var MiCV  = 0;\nvar MaCV  = 0;\nvar AvCV  = 0;\nMiCV = Number(msg.payload.MinCellVolt);\nMaCV = Number(msg.payload.MaxCellVolt);\nAvCV = Number(msg.payload.AvgCellVolt);\nmsg.payload =\n{\n    MiCV: MiCV,\n    MaCV: MaCV,\n    AvCV: AvCV,\n}\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "x": 1170,
        "y": 220,
        "wires": [
            [
                "ad2c8772.107fa8",
                "25fa4777.c5eb08"
            ]
        ]
    },
    {
        "id": "ad2c8772.107fa8",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 1650,
        "y": 220,
        "wires": []
    },
    {
        "id": "76bfaed9.eb6",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Shunt_C_V_W Influx",
        "func": "var ShuntV  = 0;\nvar ShuntC  = 0;\nvar myCurrent = 0;\nvar myVoltage = 0;\nvar Watts = 0;\nShuntV = Number(msg.payload.ShuntVoltage);\nShuntC = Number(msg.payload.ShuntCurrent);\nmyCurrent = Number(msg.payload.ShuntCurrent);\nmyVoltage = Number(msg.payload.ShuntVoltage);\nWatts=myVoltage*myCurrent;\nmsg.payload =\n{\n    ShuntV: ShuntV,\n    ShuntC: ShuntC,\n    Watts: Watts,\n}\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 1160,
        "y": 180,
        "wires": [
            [
                "71217755.f344d8",
                "c324df89.b0e6c"
            ]
        ]
    },
    {
        "id": "71217755.f344d8",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "bafffa78.f7bbc8",
        "name": "Shunt_C_V_W",
        "measurement": "Shunt_C_V_W",
        "precision": "",
        "retentionPolicy": "",
        "database": "",
        "retentionPolicyV18Flux": "",
        "org": "",
        "bucket": "",
        "x": 1440,
        "y": 160,
        "wires": []
    },
    {
        "id": "c324df89.b0e6c",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 1650,
        "y": 180,
        "wires": []
    },
    {
        "id": "6476769.7ee5988",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Shunt_Cap_F_E_SOC Influx",
        "func": "var CtoF  = 0;\nvar CtoE  = 0;\nvar SOC  = 0;\nCtoF = Number(msg.payload.NomCapacityToFull);\nCtoE = Number(msg.payload.NomCapacityToEmpty);\nSOC = Number(msg.payload.ShuntSOC);\nmsg.payload =\n{\n   CtoF: CtoF,\n   CtoE: CtoE,\n    SOC: SOC,\n}\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "x": 1180,
        "y": 680,
        "wires": [
            [
                "2ee7190.18693e8",
                "9c618b31.f4dd78"
            ]
        ]
    },
    {
        "id": "2ee7190.18693e8",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 1650,
        "y": 680,
        "wires": []
    },
    {
        "id": "9c618b31.f4dd78",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "bafffa78.f7bbc8",
        "name": "Shunt_Cap_F_E_SOC",
        "measurement": "Shunt_Cap_F_E_SOC",
        "precision": "",
        "retentionPolicy": "",
        "x": 1460,
        "y": 700,
        "wires": []
    },
    {
        "id": "25fa4777.c5eb08",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "bafffa78.f7bbc8",
        "name": "Cell_Min_Max_Avg",
        "measurement": "Cell_Min_Max_Avg",
        "precision": "",
        "retentionPolicy": "",
        "x": 1450,
        "y": 200,
        "wires": []
    },
    {
        "id": "63dc95b5.2a2dcc",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Shunt_Status Influx",
        "func": "var SS;\nSS = (msg.payload.ShuntStatus);\nmsg.payload =\n{\n  SS: SS,\n}\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "x": 1150,
        "y": 720,
        "wires": [
            [
                "b2e669b.0600398",
                "3f760caf.ca21e4"
            ]
        ]
    },
    {
        "id": "b2e669b.0600398",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 1650,
        "y": 720,
        "wires": []
    },
    {
        "id": "3f760caf.ca21e4",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "bafffa78.f7bbc8",
        "name": "Shunt_Status",
        "measurement": "Shunt_Status",
        "precision": "",
        "retentionPolicy": "",
        "x": 1480,
        "y": 740,
        "wires": []
    },
    {
        "id": "7e92a896.171e58",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "DailySessionShuntPeak_C_D Influx",
        "func": "var DSSPD  = 0;\nvar DSSPC  = 0;\nDSSPC = Number(msg.payload.DailySessionShuntPeakCharge);\nDSSPD = Number(msg.payload.DailySessionShuntPeakDischg);\nmsg.payload =\n{\n    ShuntPeakCharge: DSSPC,\n    ShuntPeakDischg: DSSPD,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 1200,
        "y": 580,
        "wires": [
            [
                "f0f77762.36efe8",
                "37822374.97f4ec"
            ]
        ]
    },
    {
        "id": "f0f77762.36efe8",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "bafffa78.f7bbc8",
        "name": "ShuntPeak_C_D",
        "measurement": "ShuntPeak_C_D",
        "precision": "",
        "retentionPolicy": "",
        "x": 1470,
        "y": 620,
        "wires": []
    },
    {
        "id": "37822374.97f4ec",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 1650,
        "y": 580,
        "wires": []
    },
    {
        "id": "ee919253.daba5",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 1650,
        "y": 920,
        "wires": []
    },
    {
        "id": "43701535.84212c",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1650,
        "y": 60,
        "wires": []
    },
    {
        "id": "739bdfbd.80809",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "ShuntVoltage",
        "func": "var myNumber = 0;\nmyNumber = Number(msg.payload.ShuntVoltage);\nreturn { payload : myNumber.toFixed(2) };",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 1130,
        "y": 260,
        "wires": [
            [
                "d29957c5.1270e8",
                "869abefc.09573",
                "51929c.16d05d64"
            ]
        ]
    },
    {
        "id": "d29957c5.1270e8",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1650,
        "y": 260,
        "wires": []
    },
    {
        "id": "8fce0a5e.09d718",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "ShuntCurrent",
        "func": "var myNumber = 0;\nmyNumber = Number(msg.payload.ShuntCurrent);\nreturn { payload : myNumber.toFixed(2) };",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 1130,
        "y": 300,
        "wires": [
            [
                "8c0ce1a3.2b188",
                "5049668e.8aca08",
                "f3feb017.6f298"
            ]
        ]
    },
    {
        "id": "8c0ce1a3.2b188",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 300,
        "wires": []
    },
    {
        "id": "bdb0b97d.26f5c8",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "d": true,
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload",
        "targetType": "msg",
        "x": 1650,
        "y": 340,
        "wires": []
    },
    {
        "id": "ab145d35.a525d",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "ShuntWatts",
        "func": "var myCurrent = 0;\nvar myVoltage = 0;\nvar myWatts = 0;\n\nmyCurrent = Number(msg.payload.ShuntCurrent);\nmyVoltage = Number(msg.payload.ShuntVoltage);\n\nmyWatts=myVoltage*myCurrent;\n\nreturn { payload : myWatts.toFixed(2) };",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 1130,
        "y": 340,
        "wires": [
            [
                "bdb0b97d.26f5c8",
                "f81ecab4.48ca38"
            ]
        ]
    },
    {
        "id": "5049668e.8aca08",
        "type": "ui_text",
        "z": "e6fd3a1c.5e9548",
        "group": "605bdeca.e6347",
        "order": 3,
        "width": "0",
        "height": "0",
        "name": "Shunt Amps: ",
        "label": "Shunt Amps: ",
        "format": "{{msg.payload}}A",
        "layout": "col-center",
        "x": 1430,
        "y": 320,
        "wires": []
    },
    {
        "id": "869abefc.09573",
        "type": "ui_text",
        "z": "e6fd3a1c.5e9548",
        "group": "605bdeca.e6347",
        "order": 2,
        "width": "0",
        "height": "0",
        "name": "Shunt Volts: ",
        "label": "Shunt Volts: ",
        "format": "{{msg.payload}}v",
        "layout": "col-center",
        "x": 1430,
        "y": 280,
        "wires": []
    },
    {
        "id": "f81ecab4.48ca38",
        "type": "ui_text",
        "z": "e6fd3a1c.5e9548",
        "group": "605bdeca.e6347",
        "order": 4,
        "width": "0",
        "height": "0",
        "name": "Shunt Watts: ",
        "label": "Shunt Watts: ",
        "format": "{{msg.payload}}W",
        "layout": "col-center",
        "x": 1430,
        "y": 360,
        "wires": []
    },
    {
        "id": "51929c.16d05d64",
        "type": "ui_gauge",
        "z": "e6fd3a1c.5e9548",
        "name": "Shunt V",
        "group": "b37bd0d4.0bb66",
        "order": 7,
        "width": 0,
        "height": 0,
        "gtype": "gage",
        "title": "Shunt V",
        "label": "units",
        "format": "{{value}}",
        "min": "40",
        "max": "60",
        "colors": [
            "#eb3d1e",
            "#e6e600",
            "#52cb3a"
        ],
        "seg1": "",
        "seg2": "",
        "x": 1280,
        "y": 280,
        "wires": []
    },
    {
        "id": "f3feb017.6f298",
        "type": "ui_gauge",
        "z": "e6fd3a1c.5e9548",
        "name": "Shunt A",
        "group": "e2c441d6.9e1ae",
        "order": 0,
        "width": 0,
        "height": 0,
        "gtype": "gage",
        "title": "Shunt A",
        "label": "units",
        "format": "{{value}}",
        "min": "-50",
        "max": "50",
        "colors": [
            "#b31200",
            "#e6e600",
            "#54c00c"
        ],
        "seg1": "",
        "seg2": "",
        "x": 1280,
        "y": 320,
        "wires": []
    },
    {
        "id": "d54ad04d.f5cb8",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "16 Cell ",
        "func": "var ONE = Number(global.get('ONE')) || 0;\nvar TWO = Number(global.get('TWO')) || 0;\nvar THREE = Number(global.get('THREE')) || 0;\nvar FOUR = Number(global.get('FOUR')) || 0;\nvar FIVE = Number(global.get('FIVE')) || 0;\nvar SIX = Number(global.get('SIX')) || 0;\nvar SEVEN = Number(global.get('SEVEN')) || 0;\nvar EIGHT = Number(global.get('EIGHT')) || 0;\nvar NINE = Number(global.get('NINE')) || 0;\nvar TEN = Number(global.get('TEN')) || 0;\nvar ELEVEN = Number(global.get('ELEVEN')) || 0;\nvar TWELVE = Number(global.get('TWELVE')) || 0;\nvar THIRTEEN = Number(global.get('THIRTEEN')) || 0;\nvar FOURTEEN = Number(global.get('FOURTEEN')) || 0;\nvar FIFTEEN = Number(global.get('FIFTEEN')) || 0;\nvar SIXTEEN = Number(global.get('SIXTEEN')) || 0;\n\nvar m = {};\nm.series = [\"B1\", \"B2\"];\nm.data = [ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN, SIXTEEN];\nm.labels = [\"\"];\nreturn {payload:[m],topic:msg.topic};",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 800,
        "y": 60,
        "wires": [
            [
                "5c74ba3e.11c214"
            ]
        ]
    },
    {
        "id": "9a44bb7a.474bd8",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Est to full/empty min influx",
        "func": "var EDF;\nvar EDE;\nEDF = (msg.payload.EstDurationToFullmins);\nEDE = (msg.payload.EstDurationToEmptymins);\nmsg.payload =\n{\n  EDF: EDF,\n  EDE: EDE,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "x": 1170,
        "y": 460,
        "wires": [
            [
                "b2853dfb.645d9",
                "d280fff4.b0597"
            ]
        ]
    },
    {
        "id": "b2853dfb.645d9",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "x": 1650,
        "y": 460,
        "wires": []
    },
    {
        "id": "d280fff4.b0597",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "bafffa78.f7bbc8",
        "name": "EST-Full_Empty_Min",
        "measurement": "EST-Full_Empty_Min",
        "precision": "",
        "retentionPolicy": "",
        "x": 1460,
        "y": 480,
        "wires": []
    },
    {
        "id": "90437fe0.fcd83",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Test",
        "func": "var EDTF;\nvar EDTE;\nEDTF = (msg.payload.EstDurationToFullmins);\nEDTE = (msg.payload.EstDurationToEmptymins);\nmsg.payload =\n{\n  EDTF: EDTF,\n  EDTE: EDTE,\n}\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "x": 1510,
        "y": 840,
        "wires": [
            [
                "df5c7d37.bd20b"
            ]
        ]
    },
    {
        "id": "5c74ba3e.11c214",
        "type": "ui_chart",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "group": "b0f57fc2.e496c",
        "order": 0,
        "width": 0,
        "height": 0,
        "label": "chart",
        "chartType": "bar",
        "legend": "false",
        "xformat": "HH:mm:ss",
        "interpolate": "linear",
        "nodata": "",
        "dot": false,
        "ymin": "3",
        "ymax": "4.2",
        "removeOlder": 1,
        "removeOlderPoints": "",
        "removeOlderUnit": "3600",
        "cutout": 0,
        "useOneColor": false,
        "useUTC": false,
        "colors": [
            "#1f77b4",
            "#aec7e8",
            "#ff7f0e",
            "#2ca02c",
            "#98df8a",
            "#d62728",
            "#ff9896",
            "#9467bd",
            "#c5b0d5"
        ],
        "outputs": 1,
        "x": 950,
        "y": 60,
        "wires": [
            []
        ]
    },
    {
        "id": "605bdeca.e6347",
        "type": "ui_group",
        "name": "16 Cell",
        "tab": "f3fb9943.a12128",
        "order": 2,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "bafffa78.f7bbc8",
        "type": "influxdb",
        "hostname": "localhost",
        "port": "8086",
        "protocol": "http",
        "database": "batrium",
        "name": "",
        "usetls": false,
        "tls": "",
        "influxdbVersion": "1.x",
        "url": "",
        "rejectUnauthorized": false
    },
    {
        "id": "b37bd0d4.0bb66",
        "type": "ui_group",
        "name": "ShuntV",
        "tab": "f3fb9943.a12128",
        "order": 3,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "e2c441d6.9e1ae",
        "type": "ui_group",
        "name": "Shunt A",
        "tab": "f3fb9943.a12128",
        "order": 1,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "b0f57fc2.e496c",
        "type": "ui_group",
        "name": "7 Cell",
        "tab": "f3fb9943.a12128",
        "order": 4,
        "disp": true,
        "width": "6",
        "collapse": false
    },
    {
        "id": "f3fb9943.a12128",
        "type": "ui_tab",
        "name": "Watchmon",
        "icon": "dashboard",
        "order": 2,
        "disabled": false,
        "hidden": false
    }
]
Categories
Uncategorized

Mate3 node-red JSON

For use with ingesting Mate3 JSON into node-red

[
    {
        "id": "2dd56da2.048d82",
        "type": "http request",
        "z": "e6fd3a1c.5e9548",
        "name": "Mate3",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "http://<mate3IP>/Dev_status.cgi?Port=0%20A",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "x": 290,
        "y": 1660,
        "wires": [
            [
                "d40648f9.b12dc8",
                "d026a702.9231f8",
                "5077acd5.17a9c4",
                "7777fab6.2a3ae4",
                "11634c6d.b4afd4",
                "29e7a5db.b29d9a",
                "cb2a046e.8303a8",
                "fd82fc3e.a0d6b",
                "55cc3d2.1525cc4",
                "794e591c.f05aa8",
                "4c5cf16f.6d369",
                "1ef81d42.82e973",
                "1fb8afd6.a5678"
            ]
        ]
    },
    {
        "id": "8511eb15.b245c8",
        "type": "inject",
        "z": "e6fd3a1c.5e9548",
        "name": "5 sec",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "5",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 150,
        "y": 1660,
        "wires": [
            [
                "2dd56da2.048d82"
            ]
        ]
    },
    {
        "id": "d40648f9.b12dc8",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.devstatus.ports[0].VAC_out",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1000,
        "y": 1420,
        "wires": []
    },
    {
        "id": "d026a702.9231f8",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.devstatus.ports[0].Inv_I",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 990,
        "y": 1460,
        "wires": []
    },
    {
        "id": "47933888.201778",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "abf95fe7.620b8",
        "name": "fx60",
        "measurement": "fx60",
        "precision": "",
        "retentionPolicy": "",
        "database": "",
        "retentionPolicyV18Flux": "",
        "org": "",
        "bucket": "",
        "x": 890,
        "y": 1880,
        "wires": []
    },
    {
        "id": "7dd099d5.4cca98",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "Inv1 kW Output",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.inv1kw",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 700,
        "y": 1420,
        "wires": []
    },
    {
        "id": "5077acd5.17a9c4",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Inv1 kW",
        "func": "var inv1kw  = 0;\n\ninv1kw = Number(msg.payload.devstatus.ports[0].VAC_out * msg.payload.devstatus.ports[0].Inv_I);\nmsg.payload =\n{\n    inv1kw: inv1kw,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 480,
        "y": 1420,
        "wires": [
            [
                "7dd099d5.4cca98",
                "d0e6c69.2398638"
            ]
        ]
    },
    {
        "id": "7777fab6.2a3ae4",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.devstatus.ports[1].VAC_out",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1000,
        "y": 1500,
        "wires": []
    },
    {
        "id": "11634c6d.b4afd4",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.devstatus.ports[1].Inv_I",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 990,
        "y": 1540,
        "wires": []
    },
    {
        "id": "d5eac968.26ae98",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "Inv2 kW Output",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.inv2kw",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 700,
        "y": 1500,
        "wires": []
    },
    {
        "id": "29e7a5db.b29d9a",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Inv2 kW",
        "func": "var inv2kw  = 0;\n\ninv2kw = Number(msg.payload.devstatus.ports[1].VAC_out * msg.payload.devstatus.ports[1].Inv_I);\nmsg.payload =\n{\n    inv2kw: inv2kw,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 480,
        "y": 1500,
        "wires": [
            [
                "d5eac968.26ae98",
                "c1420abe.d91588"
            ]
        ]
    },
    {
        "id": "cb2a046e.8303a8",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.devstatus.ports[2].VAC_out",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 1000,
        "y": 1580,
        "wires": []
    },
    {
        "id": "fd82fc3e.a0d6b",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.devstatus.ports[2].Inv_I",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 990,
        "y": 1620,
        "wires": []
    },
    {
        "id": "1053084e.e783d8",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "Inv3 kW Output",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.inv3kw",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 700,
        "y": 1580,
        "wires": []
    },
    {
        "id": "55cc3d2.1525cc4",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Inv3 kW",
        "func": "var inv3kw  = 0;\n\ninv3kw = Number(msg.payload.devstatus.ports[2].VAC_out * msg.payload.devstatus.ports[2].Inv_I);\nmsg.payload =\n{\n    inv3kw: inv3kw,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 480,
        "y": 1580,
        "wires": [
            [
                "1053084e.e783d8",
                "f854290d.65a438"
            ]
        ]
    },
    {
        "id": "f22635ce.61c368",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "FX60 kW Output",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.fx60",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 700,
        "y": 1900,
        "wires": []
    },
    {
        "id": "794e591c.f05aa8",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "FX60 kW",
        "func": "var fx60  = 0;\n\nfx60 = Number(msg.payload.devstatus.ports[3].Out_I * msg.payload.devstatus.ports[3].Batt_V);\nmsg.payload =\n{\n    fx60: fx60,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 480,
        "y": 1900,
        "wires": [
            [
                "f22635ce.61c368",
                "47933888.201778"
            ]
        ]
    },
    {
        "id": "824e1c12.ca1cb",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "MX60 kW Output",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.mx60",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 710,
        "y": 1940,
        "wires": []
    },
    {
        "id": "4c5cf16f.6d369",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "MX60 kW",
        "func": "var mx60  = 0;\n\nmx60 = Number(msg.payload.devstatus.ports[4].Out_I * msg.payload.devstatus.ports[4].Batt_V);\nmsg.payload =\n{\n    mx60: mx60,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 480,
        "y": 1940,
        "wires": [
            [
                "824e1c12.ca1cb",
                "e370423c.c096c"
            ]
        ]
    },
    {
        "id": "6a457149.45b0e",
        "type": "comment",
        "z": "e6fd3a1c.5e9548",
        "name": "Solar Charge Controllers",
        "info": "",
        "x": 530,
        "y": 1840,
        "wires": []
    },
    {
        "id": "d46dc3e5.1433e",
        "type": "comment",
        "z": "e6fd3a1c.5e9548",
        "name": "3.5kW Inverters",
        "info": "",
        "x": 500,
        "y": 1380,
        "wires": []
    },
    {
        "id": "1ef81d42.82e973",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "Total PV",
        "func": "var totalpv  = 0;\n\ntotalpv = Number(msg.payload.devstatus.ports[3].Out_I * msg.payload.devstatus.ports[3].Batt_V) + (msg.payload.devstatus.ports[4].Out_I * msg.payload.devstatus.ports[4].Batt_V);\nmsg.payload =\n{\n    totalpv: totalpv,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 480,
        "y": 1980,
        "wires": [
            [
                "e3da2252.bb595",
                "4613b28e.2d915c"
            ]
        ]
    },
    {
        "id": "e3da2252.bb595",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "Total PV kW",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.totalpv",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 690,
        "y": 1980,
        "wires": []
    },
    {
        "id": "e370423c.c096c",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "abf95fe7.620b8",
        "name": "mx60",
        "measurement": "mx60",
        "precision": "",
        "retentionPolicy": "",
        "database": "",
        "retentionPolicyV18Flux": "",
        "org": "",
        "bucket": "",
        "x": 890,
        "y": 1920,
        "wires": []
    },
    {
        "id": "4613b28e.2d915c",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "abf95fe7.620b8",
        "name": "totalpv",
        "measurement": "totalpv",
        "precision": "",
        "retentionPolicy": "",
        "database": "",
        "retentionPolicyV18Flux": "",
        "org": "",
        "bucket": "",
        "x": 890,
        "y": 1960,
        "wires": []
    },
    {
        "id": "c1420abe.d91588",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "abf95fe7.620b8",
        "name": "inv2",
        "measurement": "inv2",
        "precision": "",
        "retentionPolicy": "",
        "database": "",
        "retentionPolicyV18Flux": "",
        "org": "",
        "bucket": "",
        "x": 670,
        "y": 1460,
        "wires": []
    },
    {
        "id": "f854290d.65a438",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "abf95fe7.620b8",
        "name": "inv3",
        "measurement": "inv3",
        "precision": "",
        "retentionPolicy": "",
        "database": "",
        "retentionPolicyV18Flux": "",
        "org": "",
        "bucket": "",
        "x": 670,
        "y": 1540,
        "wires": []
    },
    {
        "id": "d0e6c69.2398638",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "abf95fe7.620b8",
        "name": "inv1",
        "measurement": "inv1",
        "precision": "",
        "retentionPolicy": "",
        "database": "",
        "retentionPolicyV18Flux": "",
        "org": "",
        "bucket": "",
        "x": 670,
        "y": 1380,
        "wires": []
    },
    {
        "id": "1fb8afd6.a5678",
        "type": "function",
        "z": "e6fd3a1c.5e9548",
        "name": "totalinv",
        "func": "var totalinv  = 0;\n\ntotalinv = Number(msg.payload.devstatus.ports[0].VAC_out * msg.payload.devstatus.ports[0].Inv_I)+(msg.payload.devstatus.ports[1].VAC_out * msg.payload.devstatus.ports[1].Inv_I)+(msg.payload.devstatus.ports[2].VAC_out * msg.payload.devstatus.ports[2].Inv_I);\nmsg.payload =\n{\n    totalinv: totalinv,\n}\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "x": 480,
        "y": 1680,
        "wires": [
            [
                "88aa435.7052fc",
                "5f2e3490.d93b9c"
            ]
        ]
    },
    {
        "id": "88aa435.7052fc",
        "type": "debug",
        "z": "e6fd3a1c.5e9548",
        "name": "totalinv",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "payload.totalinv",
        "targetType": "msg",
        "statusVal": "",
        "statusType": "auto",
        "x": 900,
        "y": 1660,
        "wires": []
    },
    {
        "id": "5f2e3490.d93b9c",
        "type": "influxdb out",
        "z": "e6fd3a1c.5e9548",
        "influxdb": "abf95fe7.620b8",
        "name": "totalinv",
        "measurement": "totalinv",
        "precision": "",
        "retentionPolicy": "",
        "database": "",
        "retentionPolicyV18Flux": "",
        "org": "",
        "bucket": "",
        "x": 680,
        "y": 1640,
        "wires": []
    },
    {
        "id": "abf95fe7.620b8",
        "type": "influxdb",
        "hostname": "127.0.0.1",
        "port": "8086",
        "protocol": "http",
        "database": "mate",
        "name": "",
        "usetls": false,
        "tls": "b56a2f8c.4744d",
        "influxdbVersion": "1.x",
        "url": "http://localhost:8086",
        "rejectUnauthorized": true
    },
    {
        "id": "b56a2f8c.4744d",
        "type": "tls-config",
        "name": "local-tls",
        "cert": "",
        "key": "",
        "ca": "",
        "certname": "",
        "keyname": "",
        "caname": "",
        "verifyservercert": false
    }
]
Categories
Batteries

Ingesting Mate3 JSON into node-red

Get data from your Mate3 data into your InfluxDB database.

This guide assumes that you have already set up a RPi4 with InfluxDB + “batrium” user, node-red, grafana, etc. and know how to use the Pi’s CLI.

Head into your Pi4 CLI, we need to create another Influx database for the Mate3 data we’re about to grab.

influx 

#type 'influx' you will notice a different CLI prompt. This is normal, you are now in the influx CLI.

create database mate

grant all on mate to batrium

show databases

show users

exit

influx -username 'batrium' -password '123456' -database mate

exit

Congratulations, you now have an empty Mate3 database for all of your tasty data!

Importing the Mate3 flow into node-red

Open Node-Red in your PC web browser.
IP address of your Pi4 into your URL bar, suffixed with :1880- ie, 10.7.0.47:1880
In the top-right menu icon, click on Manage palette.

  • Click HERE to download the Mate3 flow JSON

Import the Mate3 flow json by clicking the top right menu icon, then click on import.

Past in the Mate3 JSON file, import to “new flow”, and click “import”

Your page should look something like this.

How this flow works, and what you need to change.

From left to right;

  1. Blue inject node “5 sec” tells the flow to run every five seconds.
  2. Yellow http request node “Mate3” “GET”s data from your Mate3 JSON, and returns a parsed JSON object
  3. Orange function nodes grab individual lines of data from the Mate3 JSON
  4. Grey influxdb out nodes send those individual lines of data from node-red into your “mate” Influxdb database.

So the first step we need to fix is to tell the http request node where your JSON file with all of the Mate3 data is – ie, what the IP address of your Mate3 address is.

For what it’s worth, here is Outback Solar’s documentation for programming the Mate3.

For most people, there is no easy way to find this address. I personally use a Unifi network, so I can easily check the IP address of the Mate3 device (called AlphaTec) in my Unifi app.

You could perhaps log into your router and check a list of connected devices, find “AlphaTec“, and copy the IP address down.

Alternatively, you could use a piece of free-trial software called “Solarwinds IP Address Manager”.

However you do it, you NEED to get this IP address – in my case, it’s 10.0.0.66

Our Mate3 IP address is 10.0.0.66

Using Chrome, install JSON Viewer, or any other extension that auto-formats JSON files.

Take this IP address, append /Dev_status.cgi?Port=0 to the end of it, and paste it (http://<mateIPaddress>/Dev_status.cgi?Port=0%20A) into your web browser to confirm that it’s the correct address.

If all goes to plan, you’ll be greeted by something like this:

Therefore, our Mate3 JSON file is located at
http://<mateIPaddress>/Dev_status.cgi?Port=0%20A

If it didn’t work, then you may want to double check to ensure you got the correct IP address. If you’re SURE that it’s the correct IP address, then perhaps you have a firewall blocking traffic across your network and I can’t help you – may as well give up now.

Assuming it DID work, it’s VERY important that you remove the “&” in front of “Port=0”, if it’s present when using the address URL from here on in.

For whatever reason, it’s an error introduced to the URL that Chrome can remove automatically, but it’ll stop the URL from working once inside node-red.


Take the address of your Mate3’s JSON (in our case, it’s http://10.1.1.66/Dev_status.cgi?Port=0%20A) and enter it in the Mate3 node settings page, as per below.
Ensure that;

  1. Method = GET
  2. Payload = Ignore
  3. Return = a parsed JSON object
  4. Name = Mate3

Congrats! If everything went to plan, then your node-red flow is ingesting data from your Mate3!

And now is the hard part…


Telling node-red to grab the right JSON data.

Everyone’s setup is different, so here is where you need to get “coding”.
Below is the JSON data from my Mate3.

{
  "devstatus": {
    "Gateway_Type": "Mate3s",
    "Sys_Time": 1610996763,
    "Sys_Batt_V": 25.8,
    "ports": [
      {
        "Port": 1,
        "Dev": "FX",
        "Type": "230V",
        "Inv_I": 4,
        "Chg_I": 0,
        "Buy_I": 0,
        "Sell_I": 0,
        "VAC_in": 0,
        "VAC_out": 232,
        "Batt_V": 25.8,
        "AC_mode": "NO AC",
        "INV_mode": "Inverting",
        "Warn": [
          "Temp Sensor Fail"
        ],
        "Error": [
          "none"
        ],
        "AUX": "disabled"
      },
      {
        "Port": 2,
        "Dev": "FX",
        "Type": "230V",
        "Inv_I": 0,
        "Chg_I": 0,
        "Buy_I": 0,
        "Sell_I": 0,
        "VAC_in": 0,
        "VAC_out": 224,
        "Batt_V": 26.0,
        "AC_mode": "NO AC",
        "INV_mode": "Off",
        "Warn": [
          "Temp Sensor Fail"
        ],
        "Error": [
          "none"
        ],
        "AUX": "disabled"
      },
      {
        "Port": 3,
        "Dev": "FX",
        "Type": "230V",
        "Inv_I": 0,
        "Chg_I": 0,
        "Buy_I": 0,
        "Sell_I": 0,
        "VAC_in": 0,
        "VAC_out": 226,
        "Batt_V": 26.0,
        "AC_mode": "NO AC",
        "INV_mode": "Off",
        "Warn": [
          "Temp Sensor Fail",
          "Fan Failure"
        ],
        "Error": [
          "none"
        ],
        "AUX": "disabled"
      },
      {
        "Port": 9,
        "Dev": "CC",
        "Type": "FM60/80",
        "Out_I": 4.2,
        "In_I": 1,
        "Batt_V": 25.9,
        "In_V": 73.0,
        "Out_kWh": 8.7,
        "Out_AH": 330,
        "CC_mode": "Bulk  ",
        "Error": [
          "none"
        ],
        "Aux_mode": "Manual",
        "AUX": "disabled"
      },
      {
        "Port": 10,
        "Dev": "CC",
        "Type": "MX60",
        "Out_I": 2.0,
        "In_I": 0,
        "Batt_V": 25.9,
        "In_V": 68.8,
        "Out_kWh": 6.0,
        "CC_mode": "Bulk  ",
        "Error": [
          "none"
        ],
        "Aux_mode": "Disabled",
        "AUX": "disabled"
      }
    ]
  }
}

You can see that ports 1,2,3 are VFX3524 inverters, while my two charge controllers are on ports 9 and 10.

If we look at the “Function” tab of the orange Inv1 kW function node – which tells me how many kW my inverter is currently using – in node-red (pictured below), you’ll see some… code. Frankly, I don’t know what kind of code it is… heck, I can’t even remember how I wrote it – all I know is that it works. (but I’ll try to explain, anyway).

var inv1kw  = 0;

inv1kw = Number(msg.payload.devstatus.ports[0].VAC_out * msg.payload.devstatus.ports[0].Inv_I);
msg.payload =
{
    inv1kw: inv1kw,
}
return msg;

First we have to create/specify a variable which we want node-red to send to our influxDB “mate” database, let’s call it “inv1kw“, and assign it a starting value of 0.

Now that node-red understands that inv1kw is a variable that exists, we want it to calculate a value for it.

We tell it to assign inv1kw the value resulting from multiplying the VAC_out (volts) by the Inv_I (amps), which results in the wattage out.

Then there is some other code, I don’t really know what it does but it works, so #yolo. If you’re copying this code to use on other variables you want to report on, just make sure that you change the “inv1kw” name to something else relevant – ie, if you wanted to know what amps are being output by your MX60 solar charge controller, you might call that variable “mxamps“.


Understanding how to point to data in your JSON.

Below is a stripped-down example of the JSON from my Mate3 inverter – I’ve removed all valued except from “Port” and “Batt_V”, and will illustrate how to refer to each of these Batt_V values in your node-red flow.

If you can’t figure out how to write code to refer to other values after this explanation, then I recommend you go find some resources on the internet regarding “JSON dot notation”.

{
  "devstatus": {
    "Gateway_Type": "Mate3s",
    "Sys_Time": 1610996763,
    "Sys_Batt_V": 25.8,
    "ports": [
      {
        "Port": 1,
        "Batt_V": 25.8,
      },
      {
        "Port": 2,
        "Batt_V": 26.0,
      },
      {
        "Port": 3,
        "Batt_V": 26.0,
      },
      {
        "Port": 9,
        "Batt_V": 25.9,
      },
      {
        "Port": 10,
        "Batt_V": 25.9,
      }
    ]
  }
}

VERY basically, JSON works upwards from 0.

On my Mate3 I am using ports 1, 2, 3, 9, 10. But any JSON query you do will “see” them in order 0, 1, 2, 3, 4

For example,
msg.payload.devstatus.ports[0].Batt_V
will see the value “25.8“, as it’s looking at the “Batt_V” of the port 0nth (aka 1st) on the list.

msg.payload.devstatus.ports[1].Port
will return “2”

msg.payload.devstatus.ports[2].Batt_V
will return “26.0”

msg.payload.devstatus.ports[3].Port
will return “2”

msg.payload.devstatus.ports[4].Batt_V
will return “25.9”

msg.payload.devstatus.ports[3].Port
will return “10”

If you can’t intuitively work out how this code works from the node-red flow, my examples above, and playing around for an hour… then I give up.

Ok, fine, last example.

To create a new output value to be displayed in grafana;

1. Look at the Mate3’s JSON to find the value you want to display – for example, we’ll use Port 1, “VAC_out”: 234
2. Create a function node to grab that value from the JSON, call it “inv1VAC”
3. Edit the function to something like this:

var inv1VAC= 0;

inv1VAC= Number(msg.payload.devstatus.ports[0].VAC_out);
msg.payload =
{
    inv1VAC: inv1VAC,
}
return msg;

4. Edit the output influxdb out node to be called “inv1VAC”, make the measurement “inv1VAC” and hit “done”. The output node will grab the “inv1VAC” and send it to your database, easy peasy.


Great, now we can move onto setting up Grafana!

Categories
Batteries

Batrium + Mate3 + Grafana : Part 4

Big thanks to;

Daniel Römer
for pioneering this method of getting Batrium data to Grafana with the watchmonUDPlistener.

Bloats
for the original Batrium node-red flow.

Wolfgang Attwenger / Dirty Optics
for building 90% of this workflow, albeit with a few speeling mistakes and for a completely different platform.

sdmtr
for helping me hack everything together.

Second Life Storage Forum

Binary-Parser info

Final thoughts.

Jesus fuck.

Table of contents.
Part 1 : Hardware configuration
Part 2 : Installing software
Part 3 : Configuring Grafana
Part 4 : Credits and final thoughts
Categories
Batteries

Batrium + Mate3 + Grafana : Part 3

Nearly there, let’s set up Grafana!

Go to Grafana in your PC browser, using the Pi4’s IP address suffixed with “:3000”, for example:

http://<Pi4ipaddress>:3000

We now need to set up Grafana. In a nutshell, we need to do two things. First, add the influxdb data source. Secondly, import the Dashboard.

Skipped too far ahead?
Part 1 : Hardware configuration
Part 2 : Installing software
Part 3 : Configuring Grafana
Part 4 : Credits and final thoughts
Click on the cog, and then “Data Sources”
Add new data source (ignore the existing batrium datasource in this screenshot)
Search for “InfluxDB” in the search bar, and click on “select”
URL: http://127.0.0.1:8086
Database: batrium
User: batrium
Pass: 123456
Doing the same for Mate3? Simply create another database connection and put “mate” in the database field.

Now to install the dashboard

Click on Dashboards -> Manage
Click on the blue “Import” button.
Paste in the dashboard JSON data linked above, and hit the blue “Load” button.

And tharrr she blows!

Click here to go to Part 4: Credits and tidbits

Categories
Batteries

Batrium + Mate3 + Grafana : Part 2

Finally, the fun part.

In this guide, I will be using code blocks to show you what to enter into the command line interface (CLI), illustrated below.

sudo example-code-block -butts

# stuff prefixed with a hash is my comments

When a code block like this appears, it means that you have to enter each line individually into your CLI and hit enter.

I might add notes, just for you, which are prefaced with the hash symbol (#) – don’t put these into the CLI if you can help it.

Wanna skip ahead?
Part 1 : Hardware configuration
Part 2 : Installing software
Part 3 : Configuring Grafana
Part 4 : Credits and final thoughts

Changing your password, and enabling SSH

First we need to connect your Pi4 to your Wifi network, using the little Wifi icon on the taskbar. Select your network SSID, and enter your password.

Next we need to change your Pi4’s user password from the default, and turn on SSH so we can do the rest of the hard work from the comfort of your personal computer.

Once we get through these early stages of setting up the Pi4, you’ll be using PuTTY to access your Pi4 remotely using SSH, so you should probably install in on your PC.

Now, open the Pi4’s CLI (called terminal)

Remember, each line has to be entered separately and ENTER hit before going to the next line!

Change your password:

sudo raspi-config
#hit enter

passwd

#you will be prompted to enter your password. 
#For the purposes of this tutorial I'll use 123456 - but please, for the love of god, use something a little harder to crack.
# Do it, and hit enter. 
# You need to do this so that you're not hacked immediately once we enable SSH. 

Pi4 username and password is now Pi/1234.

Turn on SSH:

sudo systemctl enable ssh
sudo systemctl start ssh

Find out your Pi’s IP address

ifconfig
Loading Debian (Ubilinux) on the Edison - learn.sparkfun.com
There should be a block of text with “wlan0” or something similar to the left of it. You need the addr: number, in this illustration it’s 10.7.0.47.

If you’re using a wired connection, you want the “eth0” IP address. “eth” stands for ethernet. You should probably know that.

The reason it says eth0 is because in the computer language world, stuff counts from 0.

So if you have three bananas, you would count them Banana 0, Banana 1, Banana 2.

I promise this will become important later, when we’re dealing with JSON files.

It’s a very good idea to write this IP address down somewhere, as we’ll be referring to it often.

Head back to your computer, and install PuTTY.

Open PuTTY, and create a new connection by;

  1. Entering your Pi4’s IP address in the Host Name box (our example uses 10.7.0.47)
  2. Typing Pi (or whatever you want) in the Saved Sessions box.
  3. Hit “Save”, so you don’t have to type the IP address again in the future.
  4. Either double click the now saved Pi session, or make sure it’s selected and click on “Open”

to paste code into PuTTY’s CLI, copy the code from this page and right-click inside the CLI – the code should paste auto-magically!

You’ll now be presented with a CLI window, asking for your username.

Type in;

pi

The CLI will now ask you for your password, this is the password we set earlier, as an example we used 1234.

1234

then hit enter again (the password text won’t be displayed).

if everything does well, you should see something like this.

Updating everything on your before we go on.

On the now logged-in and authenticated PuTTY terminal, enter the following:

sudo apt-get update
sudo apt-get upgrade -y

If at any stage through this tutorial the CLI asks for confirmation to install/update, type Y and hit enter.

Installing Grafana

sudo apt-get install -y apt-transport-https

sudo apt-get install -y software-properties-common wget

wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee -a /etc/apt/sources.list.d/grafana.list

# that paragraph above is all a single line

sudo systemctl enable --now grafana-server

sudo /bin/systemctl daemon-reload 

sudo /bin/systemctl enable grafana-server

sudo /bin/systemctl start grafana-server 

systemctl status grafana-server.service 

sudo apt -y install ufw

sudo ufw enable

sudo ufw allow ssh

sudo ufw allow 3000/tcp

#enter admin and admin for default username, (Default will need to be reset after first login.)





Check to make sure Grafana is working

Open your PC’s web browser, and enter the IP address of your Pi4 into your URL bar, suffixed with :3000 – ie, 10.7.0.47:3000
You’ll be asked to choose a new password, for this example we’ll choose 123456.

Grafana username and password is now admin/123456.

Installing InfluxDB

get -qO- https://repos.influxdata.com/influxdb.key | sudo apt-key add -
source /etc/os-release

echo "deb https://repos.influxdata.com/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/influxdb.list

sudo apt-get update && sudo apt-get install influxdb

sudo service influxdb start

sudo systemctl enable --now influxdb 
#enable and run on system boot


sudo systemctl status influxdb 
#check status

#hit ctrl-c to close


sudo ufw allow 8086/tcp 
#This command will open the default port for Influxdb
Create InfluxDB Database for your Batrium data.
influx 

#type 'influx' you will notice a different CLI prompt. This is normal, you are now in the influx CLI.


create database batrium

create user batrium with password '123456'

grant all on batrium to batrium

show databases

show users

exit

influx -username 'batrium' -password '123456' -database batrium

exit

Congratulations, you now have an empty Batrium database!

InfluxDB username and password is now batrium/123456.

Installing node-red

get -qO- https://repos.influxdata.com/influxdb.key | sudo apt-key add -source /etc/os-release

echo "deb https://repos.influxdata.com/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/influxdb.list

sudo apt-get update && sudo apt-get install influxdb

sudo apt install nodejs

nodejs -v

sudo apt install npm

sudo npm install -g --unsafe-perm node-red node-red-admin

sudo ufw allow 1880

sudo ufw allow 18542/udp 
#Opening this port allows Node-Red to "listen" for the data from the Batrium

node-red 
#This starts node-red.


Check to make sure node-red is working

Open your PC’s web browser, and enter the IP address of your Pi4 into your URL bar, suffixed with :1880– ie, 10.7.0.47:1880

Tell node-red to boot on startup.
sudo nano /etc/systemd/system/node-red.service 
# this should open up a different graphical interface in your CLI, paste in the following
.

[Unit]
Description=Node-RED
After=syslog.target network.target

[Service]
ExecStart=/pi/local/bin/node-red
Restart=on-failure
KillSignal=SIGINT

# log output to syslog as 'node-red'
SyslogIdentifier=node-red
StandardOutput=syslog

# non-root user to run as
WorkingDirectory=/home/pi/
User=pi
Group=pi

[Install]
WantedBy=multi-user.target

#once you have pasted in the text above, hit:

ctrl-o
#this saves the file

ctrl-x
#this exits the file

sudo systemctl enable node-red 

sudo systemctl start node-red 

sudo systemctl stop node-red

#Reboot and test to ensure node-red starts up.
Installing binary-parser, required by node-red.
#Navigate to your Node-Red install folder. 

sudo -i

cd /home/pi/.node-red 
#substitute 'pi' for you current Linux user.

npm install binary-parser

#We now need to edit our Node-Red settings.js file to enable the binary-parser

sudo nano /home/pi/.node-re/settings.js 
#again substitute 'pi' for your current linux user.



#this will open up a blue text editor screen with a lot of information. You need to add some text after the following line: "functionGlobalContext:"

#This line can be found if you hit "page-down" on your keyboard around six or seven times. It's annoying.

binary_parser:require('binary-parser').Parser,

ctrl-o
ctrl-X

Y
enter

Importing the Batrium flow into node-red

Open Node-Red in your PC web browser.
IP address of your Pi4 into your URL bar, suffixed with :1880- ie, 10.7.0.47:1880
In the top-right menu icon, click on Manage palette.

You need to install two new palettes (plug-ings, basically)

  • node-red-contrib-influxdb
  • node-red-dashboard

Put these two palette names into the install tab search box, and click on “install“. Accept any prompts that come up.

  • Click HERE to copy the Batrium flow JSON

Import Batrium flow json by clicking the top right menu icon, then click on import.

Past the Batrium JSON file, import to “new flow”, and click “import”

Your node-red flow should look something like this.

Of note here is that this flow is set up to listen for the Batrium UDP data on port 18542. We opened up this UDP port during the Node-Red install. This flow is also set up for a string of 16 longmons. If you have more, you will need to edit some of the nodes to reflect this.

Feel free to hit the big red deploy button!

Now we need to Deploy the Node-Red flow and check the debug tab for any errors. If you see some “TypeErrors” then it is usually because the Binary-Parser was not installed correctly. Also, you can toggle the green msg.payload debug filters on and off to see the data being received in the debug window.

If all you’re interested in is getting data from a Batrium, click here to go to Part 3: Setting up Grafana


…or click this link to read how to set up the Mate3 JSON ingest.

Categories
Batteries

Batrium + Mate3 + Grafana : Part 1

This guide is written to collection monitoring data from a Batrium BMS (and Outback Solar Mate3) and display it on a nice dashboard accessible from any web-connected device on your home network, using a Raspberry Pi4.

(If you don’t have a Mate3, you can simply ignore all mentions of it.)

How this all will work.

  • Your Batrium is broadcasting data over your wifi at all times.

    If applicable, your Mate3 generates a JSON file which you access on your home network.

  • Node-red ingests, sorts, and saves this data in a database created by InfluxDB

  • Grafana reads this database, and displays the data in a lovely dashboard, which you can access from any web-connected device on your local wifi network.

  • Easy, right?

Assumptions made in this guide is that you have:

  • an operational solar/battery system
  • a grasp of Ohm’s law
  • all devices running and connected to your wireless network.
  • a lack of fear for the command line interface (CLI)

I have used many sources, guides, snippets, code, and images from strangers on the internet which will be linked on the final page of this guide.

Wanna skip ahead?
Part 1 : Hardware configuration
Part 2 : Installing software
Part 3 : Configuring Grafana
Part 4 : Credits and final thoughts

Overview of hardware.

In this post, we’ll go over my current hardware configuration as to give you context on why I have done some of the things in this guide.

This guide was written with the following hardware in mind:

ComponentModel
InverterVFX3524
Solar Charge ControllerMX60
Solar Charge ControllerFX60
Inverter Communications HubMate3
BMSWatchmon 4
Raspberry Pi + LCD MonitorPi 4
Windows ComputerWindows 10

If you have an older Raspberry Pi or use a different operating system on your home PC, this should guide should still work, you might just have to use different software (SSH client, IP address finder, etc).

At the very least, this guide should get you 95% of the way there.

Hardware breakdown.

Battery bank.

I am running two banks of batteries, built from 128x 202Ah 3.2v CATL LiFePO4 cells from Deligreen on Alibaba.

(This racking is re-enforced)

As our inverters are built for “24” volts and each individual LiFePO4 cell is nominally 3.2 volts, each bank is made from eight batteries in series (negative to positive to negative to positive), and each battery comprises of eight individual cells – creating a 8s8p configuration at 25.6v with 64 cells in total – bank with 12,928 amp hours at 3.2v, or 41.37kWh of available power… and we have two of these banks running in parallel.

Charge/discharge rates

If we pretend for a second that all of the specification on the cells can be believed (and we weren’t sold B-grade cells), our cells are rated at 1C charge and 3C discharge.

This means that we can theoretically charge our battery setup at a rate of 3232 amps, with a maximum discharge rate of 9696 amps (252kW at 26v!) – long story short, these batteries should theoretically be able to handle any power we throw at/ask of them… our DC breakers will trip and interconnect cables will burn out long before reaching the amp limits of our cells.

Outback Power Mate 3, Inverter(s), and Solar Charge Controller(s)

A solar charge controller takes the high voltage (40v+) from a solar photovoltaic (PV) array and turns it into a voltage compatible with your battery bank – in our case, 26v. We have a Outback Power MX60 and FX60, both capable of 60 amps each. At a battery bank voltage of 26v, this means I can bring in a maximum of 3120 watts (higher or lower battery voltages will change this maximum power input negligably).

Outback Solar MX60 Solar Charge Controller

An inverter takes the low voltage of your battery bank, and converts it to your local home voltage (whether that be 120v, 220v, 230v, 240v). I have three 3500kW inverters, which means that I have approximately 10,500kW worth of power available to use in my home. Please keep in mind that 10.5kW at 230v (in NZ) is 45.6amps, which doesn’t sound like a lot… but when that power is coming out of my batteries at 26v, it’s pulling over 400amps (!!!), which is a heck of a lot of amps to be pulling through cables if you accidentally undersized them.

OutBack VFX3524 | HES PV
Outback Solar MX3524 (35 = 3500 watts. 24 = 24v)

The Mate3 is a little compute unit which talks to all of the Outback Solar inverters and chargers, make sure they are doing the right thing. Charging the batteries to the correct voltage levels, not exceeding amp limits, let the owner know if any fans or temp sensors die prematurely (which happens annoyingly often… at a cost of $40USD per replacement fan and $30USD a sensor, yowch!)

Outback Solar Mate3
Image stolen from here.
Batrium BMS

A Batrium is a Battery Monitor System (BMS) which does what it says on the box – basically monitors all of the cells in your bank to ensure that everything is hunky dory, and cells aren’t going out of balance (ie, remain the same voltage).

This whole “remain the same voltage” wasn’t an issue in the past with lead acid batteries, which (to my limited knowledge) apparently self-balanced themselves… but I’m not lead acid expert.

The Batrium BMS we use is called the Watchmon 4 (WM4). The WM4 is a central little single board compute unit which controls a string of battery cell monitors called “Longmons“. Each Longmon is daisy chained to one another, and sits on each row of 8x paralleled cells to monitor their voltage and essentially “burn off” power if the cells ever stray away from the mean voltage of the rest of the pack. As we have two packs of 8s8p cells, we need 16 Longmons to measure each row of 8p cells.

For the purposes of this guide, any modern Watchmon model which connects to wifi should work, as long as it’s broadcasting it’s cell info over your network (ie, if you install WatchMon Toolkit and it displays your cell data, you’re gucci.)

Watchmon Toolkit Software. If you can get this running on your PC, then you’re good to go!

Finally, while I have sixteen longmons sending data to my Pi4 database, it is trivial to add more monitors to the database, which we will go into on a later step.

My setup, in all of it’s glory.
Raspberry Pi 4

The Raspberry Pi 4 (RPi4) is a tiny single-board computer which runs Linux, and should set you back $35 freedom dollars, or closer to $100 dollaryoos if you live elsewhere.. The version I have is the 2gb model and runs Linux Debian Buster, if that means anything to you. The 2gb isn’t super great if you want to do anything with a relatively heavy workload, but it works just find for the database stuff we’ll be tackling shortly.

This guide is based on Raspberry Pi OS (32-bit), Debian Buster, released on 2021-01-11. If you have a new RPi4, please use Raspberry Pi Imager to install the latest version of RPi OS onto a MicroSD card 16gb or larger.

Click here to go to
Part 2 : Installing software